1

I am currently working on my final year college project and I am stuck on what I think is a threading issue. I want to be able to run my method multiple times but each time it gets ran it should update a variable with new values. I am querying an API to get userID and then passing it into my main method by setting it as a global variable.

def setup():


    try:
        global gun_cascade, camera, frameRate, property_id, length, firstFrame, framecount,i,increment,start_Time,end_Time,statusCopy,userID

        gun_cascade = cv2.CascadeClassifier('cascade.xml')
        camera = cv2.VideoCapture('gun.mp4')
        if camera.isOpened() == False:
            print("Can't open video, isOpened is empty exiting now.")
            exit(0)
        frameRate = camera.get(5)
        property_id = int(cv2.CAP_PROP_FRAME_COUNT)
        length = int(cv2.VideoCapture.get(camera, property_id))

        firstFrame = None
        count = 0
        gun_exist = False
        increment = 0
        start_Time = 0
        end_Time = 0
        i = 0


    except Exception as e:
        print(e)
        exit(0)

Above I am setting userID to global

def decision():
    setup()
    user_object = listener.userIdListner()
    tokenId = user_object.token

    status = user_object.status
    if user_object.status == "ON":
        #status=statusCopy[:]
        #aux = copy.deepcopy(matriz)
        global statusCopy

        statusCopy = copy.deepcopy(tokenId)
        print("About to run mainscrt"+statusCopy)
        #print(type(userID))
        print(type(user_object))

        post_object = listener.mainNullPostMethod()
        post_object.null
        print(post_object.null)
        #opening a a new thread
        Thread(target = main).start()
        #post_object = listener.mainNullPostMethod()
        #post_object.null
        #print(post_object.null)


    else:
        print ("Program failed to run")

Here I am querying my API to get the userId and the status either on or off. At the moment this runs fine. But the problem is If this method is running and want to run it again with a new userID it works right up until the 'while camera.isOpened():' When I get to this point I get no error or anything

def main():


    #printing out the userid to see if it's been changed
    userID = statusCopy
    print("The current userID is "+userID)

    while isOpened:


        framecount =0
        framecount += 1
        frameId = camera.get(1) #current frame number

        (grabbed, frame) = camera.read()
        if not grabbed:
            break

        # resize the frame, convert it to grayscale, and blur it
        frame = imutils.resize(frame, width=500)
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        #gray = cv2.GaussianBlur(gray, (21, 21), 0)

        #gray = cv2.dilate(gray, None, iterations=2)

        #stuff to try in the future
        #scaleFactor=1.1, minNeighbors=5, minSize=(30, 30), flags=cv2.CASCADE_SCALE_IMAGE, outputRejectLevels = True
        gun = gun_cascade.detectMultiScale(gray, 3,5)

        for (x,y,w,h) in gun:
            randID = uuid.uuid4().hex
            frame = cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)

            roi_gray = gray[y:y+h, x:x+w]
            roi_color = frame[y:y+h, x:x+w]
            rects = gun[0]
            neighbours = gun[0]
            weights = gun[0]
           if (frameId % math.floor(frameRate) == 1):
                cv2.putText(frame, datetime.datetime.now().strftime("%A %d %B %Y %I:%M:%S%p"),(10, frame.shape[0] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (255, 165, 0), 1)
                cv2.imwrite('bin/' + userID+'-'+randID + '.jpg', frame)
                if userID == "NULL":
                    print("failed due to user null")
                    break
                print("working on pushing images to s3"+userID)
                s3.uploadDirectory("bin/", "open-gun-recordings",userID)

                picURL = "s3bucket.com/users/screenshots/"+userID+'/'+userID+'-'+randID+'.jpg'

                text.fire(picURL)



        cv2.imshow("Security Feed", frame)
        key = cv2.waitKey(1) & 0xFF


    camera.release()
    cv2.destroyAllWindows()

Above I want to be able to have multiple instances of this method running at the same time and having a different userId for each instance.

if __name__ == '__main__':
    #mainNullPostMethod()
    #runDecision()
    while True:

        time.sleep(5)
        decision()

Any help and suggestion would be greatly appreciated. I am not the best at python so apologies if this is a stupid question

1 Answers1

1

First of all don't use global variables they are bad because it makes things difficult to track when changing from multiple functions (and in your case multiple threads) as described in this answer.

The problem I see is with initializing userID in the main function which you use to spawn threads, and the problem is that even though you initialize userID = statusCopy in main, even though you do a deepcopy in decision with statusCopy = copy.deepcopy(tokenId) it will still be overridden globally by any concurrent decision calls.

Let's imagine for a second that you call decision the first time, you initialize the userID and then you spawn a thread for main which makes use of that userID. Now I'm not sure how long it takes for main to execute but let's say for the sake of the argument that you wait for 5 seconds with the sleep and then do the whole thing again (while the first thread is still running). Now you basically change the userID with the second execution of the whole chain of functions and the first thread starts using the modified userID, which by definition is already bad practice since you wanted to use a specific userID information with your first thread. What I recommend is that you pass a deepcopy to the thread and initialize a local userID in the main, so that it does not get altered by concurrent threads.

Additionally, I'm not sure that you want to do a while True and spawn threads every 5 seconds, perhaps you should put a limit there also.

andreihondrari
  • 5,743
  • 5
  • 30
  • 59