1

I have a random number of threads being generated and my main thread needs to act as a timer in a tight loop. I would like to check if the children threads ended and if so I want to break the tight loop. However, I haven't been able to find any way to do this without blocking.

My best idea has been to use a variable equal to the random number of threads that will be created. When a thread is about to complete it should decrement the variable. Meanwhile the main thread can quickly check the variable to see if it is greater than 0, if so keep looping.

There must be a better way, I hope.

  • Are you on linux? If so this: http://www.kernel.org/doc/man-pages/online/pages/man3/pthread_tryjoin_np.3.html (from this answer http://stackoverflow.com/questions/73468/non-blocking-pthread-join/1244687#1244687) – Steve Jessop Mar 19 '11 at 12:30
  • Yes it's on Linux. Thanks I will give them a read~ –  Mar 19 '11 at 12:41
  • wish you hadn't deleted your fragmentation question, I was 80% of the way through typing a really nice answer... :) – sarnold Mar 24 '11 at 04:53

2 Answers2

2

Does your main thread need to do anything else while it's waiting? In order to fully answer your question I need a better explanation of what you want to achieve, but here are some tools that might solve your problem:

  • Checking an ordinary variable on each loop iteration. You'll need to perform some locking primitive around the check to portably ensure a memory barrier, otherwise you might read an outdated value.
  • Signals. Ugly, but you could have the worker threads send a signal to the main thread with pthread_kill, and that could interrupt whatever it's doing. You'll have to deal with issues about what actions are async-signal-safe though (none of the pthread functions are).
  • Condition variables. You could use pthread_cond_wait (or pthread_cond_timedwait if you want to take some action after a given time interval if no threads have exited).
  • Semaphores. You could just use a semaphore as an atomic counter, or use it like a condition variable.
R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • The main thread acts as a global clock, it iterates every 50 ~microseconds and updates a clock variable which the threads read from. So far I think the ordinary variable is the best idea so far but it will introduce a little delay in the loop but the exact timing of 50 microseconds isn't too important. I am synchronizing the threads with the clock which is why blocking is not acceptable. –  Mar 19 '11 at 12:39
  • @Google: if you want to synchronize threads on a timer, have you seen http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_barrier_wait.html? It's only applicable if you know how many threads are involved, though, it can't be used if threads disappear whenever they feel like it. – Steve Jessop Mar 19 '11 at 12:55
  • 1
    If your thread can sleep for 50 usec at a time, I would use `pthread_cond_timedwait` (which takes an absolute time, not a relative time, so it won't accumulate error) to wait on a condition variable signaled by the worker threads when they exit. – R.. GitHub STOP HELPING ICE Mar 19 '11 at 13:17
1

You could use either pthread_tryjoin_np or pthread_timedjoin_np which don't block, or have a timeout.

Read the man page for the exact semantics. These are Linux-specific though, non-portable as their name and the man pages state. So YMMV.

Mat
  • 202,337
  • 40
  • 393
  • 406
  • These are ugly nonportable (thus the `_np`) interfaces with zero benefits over the portable alternatives. – R.. GitHub STOP HELPING ICE Mar 19 '11 at 12:33
  • Fair enough, I somehow imagined the question was related to Linux. Reworded my answer to emphasize non-portability. – Mat Mar 19 '11 at 12:37
  • Thanks, I read the man pages-- I don't see how I can keep track of how many threads I need to join without an ordinary variable to compare how many threads have joined. –  Mar 19 '11 at 12:40
  • 1
    @Google: if I was using this, I'd make an array of `pthread_t` in the main thread. Then each time around its loop, the main thread does `tryjoin` on the first thread which has not previously returned a non-EBUSY value. If that returns EBUSY, do the main loop again. Otherwise, increment your pointer to "the first thread that has not previously finished" and `tryjoin` that. Total cost is bounded by one `tryjoin` per time around the main loop, plus one `tryjoin` per thread created. – Steve Jessop Mar 19 '11 at 12:50
  • you need not only to keep track of how many, but of exactly _which_ threads need to be waited on. i'd use some kind of list/queue structure to hold that, and dispose of the elements which are not needed any longer. Or a plain array maybe depending on the context/requirements (which are not very clear at all in your question) – Mat Mar 19 '11 at 12:51
  • @R..: main advantage over the portable alternatives is the ability to deal very simply with helper threads that might be cancelled before they complete and decrement the shared counter. That may not be needed in this case, of course. – Steve Jessop Mar 19 '11 at 12:52
  • @Steve: for cancellation, just install a cancellation handler as soon as the thread's start function is entered. If you're worried about races, you can use a barrier, but since at this point only the code that just created the thread has its thread id, it would be rather silly to cancel it anyway. – R.. GitHub STOP HELPING ICE Mar 19 '11 at 12:56
  • Thanks, I am going to give this a short-- –  Mar 19 '11 at 12:56
  • @R..: I think `pthread_tryjoin_np` is simpler than installing a cancellation handler. YMMV. That said, handling cancellation correctly can be so complex that by comparison this is nothing, so really it depends what the thread does. – Steve Jessop Mar 19 '11 at 13:01
  • @Mat: You don't necessarily need to know which threads need to be waited on. If you just care about the count and the data they operate on, you can simply create all the threads detached, and merely wait for the count to reach zero. Or you could use a barrier (and possibly a dedicated waiter thread) to achieve this. – R.. GitHub STOP HELPING ICE Mar 19 '11 at 13:10
  • @R.: not sure I understand. if you detach the threads, you can't use the `join` calls anymore, so you need a shared counter, and manipulate that in the worker threads when they're done and deal with the cancellation issue, right? Or am I missing the point entirely? (that happens a lot :-/) – Mat Mar 19 '11 at 13:16
  • Yeah, you'd need a shared counter. A semaphore would be an easy way to implement that. (`sem_post` and `sem_getvalue`). – R.. GitHub STOP HELPING ICE Mar 19 '11 at 13:26