Home > Enterprise >  Python threads stuck
Python threads stuck

Time:05-13

I'm trying to switch from one thread called CameraProcessing to another thread called ServerKeypoints and viceversa. To be precise, CameraProcessing changes a global variable called VALUE while ServerKeypoints consumes the global value by sending it via websocket to a client. To protect the global variable I've used the Condition mechanism.

I have two problems:

  1. At a certain moment the script stucks, the threads don't go forward
  2. The websocket client doesn't receive the data sent via websocket

The two threads are located in a script called main_server.py (I know that it is not the best idea and that it would be better to split these threads in different files).

main_server.py

import threading
import asyncio
import websockets
condition = threading.Condition()
VALUE = 0
FLAG = 0


class ServerKeypoints(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    async def communicate(self, websocket):
        global VALUE
        global FLAG

        while True:
            condition.acquire()
            if FLAG == 1:
                FLAG = 0
                print(f"SERVER VAL: {VALUE}")
                await websocket.send(f"{VALUE}")
                condition.notify_all()
            else:
                condition.wait()
            condition.release()

    async def main(self,):
        async with websockets.serve(self.communicate, "localhost", 9998):
            await asyncio.Future()  # run forever

    def run(self):
        asyncio.run(self.main())



class CameraProcessing(threading.Thread):
    def __init__(self) -> None:
        threading.Thread.__init__(self)
    
    def run(self):
        global VALUE
        global FLAG

        while True:
            condition.acquire()
            if FLAG == 0:
                VALUE  = 1
                print(f"CAMERA VAL: {VALUE}")
                FLAG = 1
                condition.notify_all()
            else:
                condition.wait()
            condition.release()

While client.py is written in the following way:

import websocket

def on_message(wsapp, message):
    message = message
    print(message)

wsapp = websocket.WebSocketApp("ws://localhost:9998", on_message=on_message)
while True:
    wsapp.run_forever()

In the Visual Studio Code terminal I have a result like this:

CAMERA VAL: 20301
SERVER VAL: 20301
CAMERA VAL: 20302
SERVER VAL: 20302
CAMERA VAL: 20303
SERVER VAL: 20303
CAMERA VAL: 20304
SERVER VAL: 20304
CAMERA VAL: 20305
SERVER VAL: 20305
CAMERA VAL: 20306
SERVER VAL: 20306
CAMERA VAL: 20307
SERVER VAL: 20307
CAMERA VAL: 20308
SERVER VAL: 20308
CAMERA VAL: 20309
SERVER VAL: 20309
CAMERA VAL: 20310
SERVER VAL: 20310
CAMERA VAL: 20311
SERVER VAL: 20311
CAMERA VAL: 20312
SERVER VAL: 20312
CAMERA VAL: 20313
SERVER VAL: 20313

But it does not go forward.

CodePudding user response:

As suggested by Michal Butscher in the comments, I've tried again the client script provided by the websockets module and I've modified in the following way:

import asyncio
import websockets

async def receive():
    while True:
        try:
            async with websockets.connect("ws://localhost:9998", ping_interval=None) as websocket:
                msg = await websocket.recv()
                print(f"{msg}")
        except:
            continue

if __name__ == "__main__":
    asyncio.run(receive())

Now it doesn't stuck.

I know that the combination async and thread is not a good idea but if you have alternatives to propose I will be glad to read them.

CodePudding user response:

I've used threads because they share the global variable VALUE and in order to protect it I use thread locks like Condition.

OK, but you don't need to create threads in order to use global variables. Your ServerKeypoints thread and your CameraProcessing thread never do any interesting thing concurrently with each other, so why not just have one thread that does this?

async def communicate(self, websocket):
    global VALUE

    while True:
        VALUE  = 1
        print(f"CAMERA VAL: {VALUE}")
        print(f"SERVER VAL: {VALUE}")
        await websocket.send(f"{VALUE}")

Get rid of the condition, get rid of the FLAG, get rid of the threads. It's a whole lot simpler, and (I'm pretty sure) it will do the same as what your example code does.

  • Related