0

I have what might be a quite simple problem, but I still cannot solve it.

I have the following code:

list_of_conditions = []  
def function_1():  
    time.sleep(60)  
    global list_of_conditions
    condition=list_of_conditions.pop()  
    condition.notify()  
    print("F1: Done")

def function_2():
    condition = Condition()  
    global list_of_conditions
    list_of_conditions.append(condition)
    with condition:  
       p1=Process(target=function_1, daemon=True)  
       p1.start()  
       condition.wait()
       print("Finished")

I think it is quite clear what I want to accomplish with the condition, but I have the problem that the global array is not working. I keep getting the error message:

IndexError: pop from empty list

I dont get it why the list is empty even though I have declare it as global.

  • 1
    Because you're using Multiprocessing. Processes do *not* share state. You have to share it yourself. In this instance you can just pass it in when you start function_1: there's no reason for global state. If the logic is more complicated, do proper producer/consumer with a queue. – 2e0byo Oct 26 '22 at 15:11
  • Quick aside: the `global` statement is entirely unnecessary here. You don't need `global` to refer to a global variable. You only need it if you are going to assign to it. Since you only call functions on `list_of_conditions` you're only referring to it. – Steven Rumbalski Oct 26 '22 at 15:15
  • 1
    To underline @StevenRumbalski's point: appending to (and popping from) a list is *not* the same as *binding a name to a new object*, which is what happens when you do something like `global x; x += 1`: in this case the global name 'x' is set up to point to the number 1 greater than x. Had you used `+=[condition]` you *would* have needed global (in `function_2`). Modifying the *contents* of a mutable is not the same as re-assigning the *name* to point to a *new* object, even if the end result is the same. – 2e0byo Oct 26 '22 at 15:22

1 Answers1

1

I dont get it why the list is empty

Because you're using Multiprocessing. Processes do not share mutable state: each Process starts with a blank slate, i.e. it sees the module as it was at intial evaluation. Sharing mutable state in multithreading/multiprocessing paradigms is problematic: what if two threads try to modify the same state?

Thus if you want to share state, you have to do it explicitly. In this instance you could use a queue, and set up a pool of consumers waiting for Condition()s to be sent them down the queue.

However if the logic as presented here is all that goes on, just modify function_1 to take the Condition() as an argument, and pass it through when you start the process:

def handle_condition(condition: Condition):
    ...

def call_handler():
    condition = Condition()
    # note that args is a tuple
    Process(target=handle_condition, args=(condition,)).start()

With that said, your current logic doesn't make much sense---if you're going to stop and wait for every process to run every time, why not just process in the same thread?

2e0byo
  • 5,305
  • 1
  • 6
  • 26
  • Thank you for your explanation. That solved one problem, but another one appeared :D If you have time, please take a look: https://stackoverflow.com/questions/74222512/condition-objects-should-only-be-shared-between-processes-through-inheritance – Tricker Macedonia Oct 27 '22 at 13:54