I recently wrote a program that used a simple producer / consumer pattern. He initially had an error related to the misuse of threading.Lock, which I eventually fixed. But it made me wonder if it is possible to implement a producer / consumer pattern in a carefree way.
The requirements in my case were simple:
- One thread manufacturer.
- One consumer thread.
- There is only one item in the queue.
- A manufacturer can create the next item before consuming the current one. Therefore, the current item is lost, but this is normal for me.
- A consumer may consume the current item until the next release. Therefore, the current item is consumed twice (or more), but this is normal for me.
So I wrote this:
QUEUE_ITEM = None # this is executed in one threading.Thread object def producer(): global QUEUE_ITEM while True: i = produce_item() QUEUE_ITEM = i # this is executed in another threading.Thread object def consumer(): global QUEUE_ITEM while True: i = QUEUE_ITEM consume_item(i)
My question is: is this code safe?
An immediate comment: this code is not actually blocked - I use CPython and has a GIL.
I checked the code a bit and it seemed to work. This translates into some LOAD and STORE statements, which are atomic due to the GIL. But I also know that the operation del x not atomic when x implements the __del__ method. Therefore, if my element has a __del__ method and some unpleasant planning occurs, everything may break. Or not?
Another question: what restrictions (for example, on the type of produced elements) do I need to impose in order to make the above code work fine?
My questions relate only to the theoretical possibility of using CPython and GIL quirks in order to come up with a lock (that is, the absence of locks such as threading.Lock explicitly in the code).
python thread-safety locking producer-consumer
Jasiu
source share