title: Multiple Python threads writing to single JSON file
body: <p>I am adapting the Python script in <a href="https://github.com/initialstate/pi-sensor-free-presence-detector" rel="nofollow noreferrer">this project</a> (expanded below) to a point where it updates a JSON file's elements, instead of the InitialState streamer. However, with the multiple threads that are opened by the script, it is impossible to succinctly write the data from each thread back to the file as it would be read, changed, and written back to the file in all threads at the same time. As there can only be one file, no version will ever be accurate as the last thread would override all others.  </p>
  
  <p><strong>Question: How can I update the states in the JSON based in each thread (simultaneously) without it affecting the other thread's writing operation or locking up the file?</strong></p>
  
  <p><em>JSON file contains the occupant's status that I would like to manipulate with the python script:</em></p>
  
  <pre><code>{
   "janeHome": "false",
   "johnHome": "false",
   "jennyHome": "false",
   "jamesHome": "false"
  }
  </code></pre>
  
  <p><em>This is the python script:</em>  </p>
  
  <pre><code>import subprocess
  import json
  from time import sleep
  from threading import Thread
  
  # Edit these for how many people/devices you want to track
  occupant = ["Jane","John","Jenny","James"]
  
  # MAC addresses for our phones
  address = ["11:22:33:44:55:66","77:88:99:00:11:22","33:44:55:66:77:88","99:00:11:22:33:44"]
  
  # Sleep once right when this script is called to give the Pi enough time
  # to connect to the network
  sleep(60)
  
  # Some arrays to help minimize streaming and account for devices
  # disappearing from the network when asleep
  firstRun = [1] * len(occupant)
  presentSent = [0] * len(occupant)
  notPresentSent = [0] * len(occupant)
  counter = [0] * len(occupant)
  
  # Function that checks for device presence
  def whosHere(i):
  
      # 30 second pause to allow main thread to finish arp-scan and populate output
      sleep(30)
  
      # Loop through checking for devices and counting if they're not present
      while True:
  
          # Exits thread if Keyboard Interrupt occurs
          if stop == True:
              print ("Exiting Thread")
              exit()
          else:
              pass
  
          # If a listed device address is present print
          if address[i] in output:
              print(occupant[i] + "'s device is connected")
              if presentSent[i] == 0:
  
                  # TODO: UPDATE THIS OCCUPANT'S STATUS TO TRUE
  
                  # Reset counters so another stream isn't sent if the device
                  # is still present
                  firstRun[i] = 0
                  presentSent[i] = 1
                  notPresentSent[i] = 0
                  counter[i] = 0
                  sleep(900)
              else:
                  # If a stream's already been sent, just wait for 15 minutes
                  counter[i] = 0
                  sleep(900)
          # If a listed device address is not present, print and stream
          else:
              print(occupant[i] + "'s device is not connected")
              # Only consider a device offline if it's counter has reached 30
              # This is the same as 15 minutes passing
              if counter[i] == 30 or firstRun[i] == 1:
                  firstRun[i] = 0
                  if notPresentSent[i] == 0:
  
                      # TODO: UPDATE THIS OCCUPANT'S STATUS TO FALSE
  
                      # Reset counters so another stream isn't sent if the device
                      # is still present
                      notPresentSent[i] = 1
                      presentSent[i] = 0
                      counter[i] = 0
                  else:
                      # If a stream's already been sent, wait 30 seconds
                      counter[i] = 0
                      sleep(30)
              # Count how many 30 second intervals have happened since the device 
              # disappeared from the network
              else:
                  counter[i] = counter[i] + 1
                  print(occupant[i] + "'s counter at " + str(counter[i]))
                  sleep(30)
  
  # Main thread
  try:
  
      # Initialize a variable to trigger threads to exit when True
      global stop
      stop = False
  
      # Start the thread(s)
      # It will start as many threads as there are values in the occupant array
      for i in range(len(occupant)):
          t = Thread(target=whosHere, args=(i,))
          t.start()
  
      while True:
          # Make output global so the threads can see it
          global output
  
          # Reads existing JSON file into buffer
          with open("data.json", "r") as jsonFile:
              data = json.load(jsonFile)
              jsonFile.close()
  
          # Assign list of devices on the network to "output"
          output = subprocess.check_output("arp-scan -interface en1 --localnet -l", shell=True)
  
          temp = data["janeHome"]
          data["janeHome"] = # RETURNED STATE
          data["johnHome"] = # RETURNED STATE
          data["jennyHome"] = # RETURNED STATE
          data["jamesHome"] = # RETURNED STATE
  
          with open("data.json", "w") as jsonFile:
              json.dump(data, jsonFile)
              jsonFile.close()
  
          # Wait 30 seconds between scans
              sleep(30)
  
  except KeyboardInterrupt:
      # On a keyboard interrupt signal threads to exit
      stop = True
      exit()
  </code></pre>
  
  <p>I think we can all agree that the best idea would be to return the data from each thread to the main and write it to the file in one location but here is where it gets confusing, with each thread checking for a different person, how can the state be passed back to main for writing?</p>