0

I use several threads with child-threads. Now i want to stop a parent-thread or wait until a parent thread has done its work without checking and stopping all the child threads. My thought is to wrap the parent thread with a process and then just to terminate the process, which seems to terminate the corresponding parent-thread with all its childs.

def worker(conn):

    #this is the class including the parent thread
    xi = Test_Risk_Calc('99082')
    #start working
    xi.test()    
    #finished

    print ('EVERYTHING IS DONE, BUT CHILD THREADS ARE STILL ALIVE')
    conn.send('EXIT SEND')
    return

def main():
    parent_conn, child_conn = Pipe()
    p = multiprocessing.Process(target=worker, args=(child_conn,))
    p.start()
    #wait for finished parent-thread
    print(parent_conn.recv())
    p.terminate()
    p.join()
    print('JOINED, PROCESS AND ALL ITS THREADS ARE TERMINATED')
    return

I am not sure if this is a proper way to solve the problem

Egirus Ornila
  • 1,234
  • 4
  • 14
  • 39
  • Read [multiprocessing-vs-threading-python](https://stackoverflow.com/questions/3044580/multiprocessing-vs-threading-python/3046201#3046201) – stovfl May 07 '19 at 07:37
  • threads in Python are very low-level, you might be better off with some sort of abstraction to help get these sorts of things right. which one will depend on why you're using threads at the moment – Sam Mason May 09 '19 at 15:24

1 Answers1

1

I think it's okay like you've done it. However, you can avoid the "terminate" which always is a bit "hard".

The simple solution to that would be to start the child threads with the argument "daemon = True". This actually terminates the child threads automatically if their parent terminates.

Like I said before, this might seem a bit cleaner, but in the end, it would be the same, I think.

EDIT:

Maybe consider using asyncio (async/await) for concurrent programming. You could create tasks with

task = asyncio.create_task(my_task())

and cancel these tasks later

task.cancel()

Nice thing here is, that this "cancel" throws an exception into the task. So within the task you can do stuff like this:

async def my_task():
  try:
    ... stuff ...
  except asyncio.CancelledError:
    ... you can handle the cancellation, or ignore it

In python, tasks are not very useful. For concurrent execution you can better use asyncio and if you have cpu-bound tasks you can use multiprocessing (maybe in the form of process pools).

Reductio
  • 429
  • 2
  • 8
  • Python's [Thread object docu](https://docs.python.org/3/library/threading.html#thread-objects): Daemon threads are abruptly stopped at shutdown. Their resources (such as open files, database transactions, etc.) may not be released properly. If you want your threads to stop gracefully, make them non-daemonic and use a suitable signalling mechanism such as an [Event](https://docs.python.org/3/library/threading.html#threading.Event). – shmee May 07 '19 at 07:55
  • Thanks for the link. But yes, that's what I meant. In the end it will be the same like he already did, It is still just a termination. For me declaring the children "deamon" is just the explicit statement that this is the desired behavior. – Reductio May 07 '19 at 08:17
  • No, the OP is calling `terminate` on a _process_, not a thread. Threads don't have a `terminate` method. Threads, are `join`'ed if they are non-daemonic, either explicitly by you or [implicitly during interpreter shutdown](https://github.com/python/cpython/blob/3.7/Lib/threading.py#L1280_L1282), or, in case of daemonic threads, they just end with the interpreter process. – shmee May 07 '19 at 08:32
  • I don't understand your argument. I'm aware that he calls terminate on a process. However, he describes that that process spawns child threads. The only thing I'm describing is that these child threads get terminated either way. If the parent process is terminated or if he uses daemonic threads. If deamonic threads are used, he just don't have to terminate the parent process, because according to his description, the process ends normally. So in his example the "terminate" has to be called only because there are still child threads the process is waiting for. – Reductio May 07 '19 at 08:37
  • *Oooohhh!* The requirement is to stop indefinitely running threads started by another thread that terminates on its own? I really didn't get that. You are right of course, Sorry for the confusion. My comments will self-destruct and, in case of doubt, will have never existed :D Seems like an unusual approach to use processes for this, though. – shmee May 07 '19 at 16:51