 <p>I believe <a href="http://stackoverflow.com/a/24855194/1475978">gmch's answer</a> should solve the original question. However, not all pthread implementations include <code>pthread_barrier_t</code> and the related functions (as they are an optional part of the POSIX threads specs), so here is the custom barrier implementation I mentioned in a comment to the original question.</p> <p>(Note that there are other ways to suspend/resume threads asynchronously, during normal operation, and without co-operation from the threads themselves. One way to implement that is to use one or two realtime signals, and a signal handler that blocks in <a href="http://man7.org/linux/man-pages/man2/sigsuspend.2.html" rel="nofollow"><code>sigsuspend()</code></a>, waiting for the complementary "continue" signal. The controlling thread will have to use <a href="http://man7.org/linux/man-pages/man3/pthread_kill.3.html" rel="nofollow"><code>pthread_kill()</code></a> or <a href="http://man7.org/linux/man-pages/man3/pthread_sigqueue.3.html" rel="nofollow"><code>pthread_sigqueue()</code></a> to send the pausing and continuing signals to each thread involved. The threads are minimally affected; aside from possible <code>EINTR</code> errors from blocking syscalls (as signal delivery interrupts blocking syscalls), the threads just don't do any progress -- just as if they weren't scheduled for a while. Because of that, there should not be any issues with respect to the threads getting paused and continued at slightly different times. If you are interested in this method, leave a comment, and I could try and show an example implementation of that, too.)</p> <p>Perhaps this will be of use to someone else needing a pause-able custom barrier implementation, or perhaps as a basis of their own custom barrier. </p> <p>Edited to add <code>DRAINING</code> mode, when threads are expected to quit. In your worker loop, use <code>do { ... } while (!barrier_wait(&amp;barrier));</code></p> <p><strong>barrier.h</strong>:</p> <pre><code>#ifndef BARRIER_H #define BARRIER_H #include &lt;pthread.h&gt; #include &lt;errno.h&gt; typedef enum { INVALID = -1, RUNNING = 0, PAUSED = 1, DRAINING = 2 } barrier_state; typedef struct { pthread_mutex_t mutex; pthread_cond_t cond; barrier_state state; int threads; /* Number of participants */ int waiting; /* Number of participants waiting */ } barrier; /** barrier_drain() - Mark barrier so that threads will know to exit * @b: pointer to barrier * @ids: pthread_t's for the threads to wait on, or NULL * @retvals: return values from the threads, or NULL * This function marks the barrier such that all threads arriving * at it will return ETIMEDOUT. * If @ids is specified, the threads will be joined. * Returns 0 if successful, errno error code otherwise. */ static int barrier_drain(barrier *const b, pthread_t *const ids, void **const retvals) { int result, threads; void *retval; if (!b || b-&gt;threads &lt; 0) return errno = EINVAL; result = pthread_mutex_lock(&amp;b-&gt;mutex); if (result) return errno = result; b-&gt;state = DRAINING; pthread_cond_broadcast(&amp;b-&gt;cond); threads = b-&gt;threads; b-&gt;threads = 0; pthread_mutex_unlock(&amp;b-&gt;mutex); while (threads--&gt;0) { result = pthread_join(ids[threads], &amp;retval); if (result) return errno = result; if (retvals) retvals[threads] = retval; } return errno = 0; } /** barrier_pause() - Mark barrier to pause threads in the barrier * @b: pointer to barrier * This function marks the barrier such that all threads arriving * in it will wait in the barrier, until barrier_continue() is * called on it. If barrier_continue() is called before all threads * have arrived on the barrier, the barrier will operate normally; * i.e. the threads will continue only when all threads have arrived * at the barrier. * Returns 0 if successful, errno error code otherwise. */ static int barrier_pause(barrier *const b) { int result; if (!b || b-&gt;threads &lt; 1) return errno = EINVAL; result = pthread_mutex_lock(&amp;b-&gt;mutex); if (result) return errno = result; if (b-&gt;state != PAUSED &amp;&amp; b-&gt;state != RUNNING) { pthread_mutex_unlock(&amp;b-&gt;mutex); return errno = EPERM; } b-&gt;state = PAUSED; pthread_mutex_unlock(&amp;b-&gt;mutex); return errno = 0; } /** barrier_continue() - Unpause barrier * @b: Pointer to barrier * This function lets the barrier operate normally. * If all threads are already waiting in the barrier, * it lets them proceed immediately. Otherwise, the * threads will continue when all threads have arrived * at the barrier. * Returns 0 if success, errno error code otherwise. */ static int barrier_continue(barrier *const b) { int result; if (!b || b-&gt;threads &lt; 0) return errno = EINVAL; result = pthread_mutex_lock(&amp;b-&gt;mutex); if (result) return errno = result; if (b-&gt;state != PAUSED) { pthread_mutex_unlock(&amp;b-&gt;mutex); return errno = EPERM; } b-&gt;state = RUNNING; if (b-&gt;waiting &gt;= b-&gt;threads) pthread_cond_broadcast(&amp;b-&gt;cond); pthread_mutex_unlock(&amp;b-&gt;mutex); return errno = 0; } /** barrier_wait() - Wait on the barrier * @b: Pointer to barrier * Each thread participating in the barrier * must call this function. * Callers will block (wait) in this function, * until all threads have arrived. * If the barrier is paused, the threads will * wait until barrier_continue() is called on * the barrier, otherwise they will continue * when the final thread arrives to the barrier. * Returns 0 if success, errno error code otherwise. * Returns ETIMEDOUT if the thread should exit. */ static int barrier_wait(barrier *const b) { int result; if (!b || b-&gt;threads &lt; 0) return errno = EINVAL; result = pthread_mutex_lock(&amp;b-&gt;mutex); if (result) return errno =result; if (b-&gt;state == INVALID) { pthread_mutex_unlock(&amp;b-&gt;mutex); return errno = EPERM; } else if (b-&gt;state == DRAINING) { pthread_mutex_unlock(&amp;b-&gt;mutex); return errno = ETIMEDOUT; } b-&gt;waiting++; if (b-&gt;state == RUNNING &amp;&amp; b-&gt;waiting &gt;= b-&gt;threads) pthread_cond_broadcast(&amp;b-&gt;cond); else pthread_cond_wait(&amp;b-&gt;cond, &amp;b-&gt;mutex); b-&gt;waiting--; pthread_mutex_unlock(&amp;b-&gt;mutex); return errno = 0; } /** barrier_destroy() - Destroy a previously initialized barrier * @b: Pointer to barrier * Returns zero if success, errno error code otherwise. */ static int barrier_destroy(barrier *const b) { int result; if (!b || b-&gt;threads &lt; 0) return errno = EINVAL; b-&gt;state = INVALID; b-&gt;threads = -1; b-&gt;waiting = -1; result = pthread_cond_destroy(&amp;b-&gt;cond); if (result) return errno = result; result = pthread_mutex_destroy(&amp;b-&gt;mutex); if (result) return errno = result; return errno = 0; } /** barrier_init() - Initialize a barrier * @b: Pointer to barrier * @threads: Number of threads to participate in barrier * Returns 0 if success, errno error code otherwise. */ static int barrier_init(barrier *const b, const int threads) { int result; if (!b || threads &lt; 1) return errno = EINVAL; result = pthread_mutex_init(&amp;b-&gt;mutex, NULL); if (result) return errno = result; result = pthread_cond_init(&amp;b-&gt;cond, NULL); if (result) return errno = result; b-&gt;state = RUNNING; b-&gt;threads = threads; b-&gt;waiting = 0; return errno = 0; } #endif /* BARRIER_H */ </code></pre> <p>The logic is quite simple. All threads waiting in the barrier wait on the <code>cond</code> condition variable. If the barrier operates normally (<code>state==RUNNING</code>), the final thread arriving at the barrier will broadcast on the condition variable instead of waiting on it, thus waking up all other threads.</p> <p>If the barrier is paused (<code>state==PAUSED</code>), even the final thread arriving at the barrier will wait on the condition variable.</p> <p>When <code>barrier_pause()</code> is called, the barrier state is changed to paused. There may be zero or more threads waiting on the condition variable, and that is okay: only the final thread arriving at the barrier has a special role, and that thread cannot have yet arrived. (If it had, it'd have emptied the barrier already.)</p> <p>When <code>barrier_continue()</code> is called, the barrier state is changed to normal (<code>state==RUNNING</code>). If all threads are waiting on the condition variable, they are released by broadcasting on the condition variable. Otherwise, the final thread arriving at the barrier will broadcast on the condition variable and release the waiting threads normally.</p> <p>Note that <code>barrier_pause()</code> and <code>barrier_continue()</code> do not wait for the barrier to become full or to drain. It only blocks on the mutex, and the functions only hold it for very short periods at a time. (In other words, they may block for a short time, but will not wait for the barrier to reach any specific situation.)</p> <p>If the barrier is draining (<code>state==DRAINING</code>), threads arriving at the barrier return immediately with <code>errno==ETIMEDOUT</code>. For simplicity, all the barrier functions now unconditionally set errno (to 0 if success, errno code if error, <code>ETIMEDOUT</code> if draining).</p> <p>The <code>mutex</code> protects the barrier fields so that only one thread may access the fields at once. In particular, only one thread can arrive at the barrier at the same time, due to the mutex.</p> <p>One complicated situation exists: the loop body the barrier is used in might be so short, or there might be so many threads, that threads start arriving at the next iteration of the barrier even before all threads from the previous iteration have left it.</p> <p>According to <a href="http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cond_broadcast.html" rel="nofollow">POSIX.1-2004, <code>pthread_cond_broadcast()</code></a> <em>"shall unblock all threads currently blocking on the specified condition variable"</em>. Even though their wakeups will be sequential -- as each one will acquire the mutex in turn --, only those threads that were blocked on it when <code>pthread_cond_broadcast()</code> was called will be woken up.</p> <p>So, if the implementation follows POSIX semantics with respect to condition variables, woken threads can (even immediately!) re-wait on the condition variable, waiting for the next broadcast or signal: the "old" and "new" waiters are separate sets. This use case is actually quite typical, and all POSIX implementations I've heard of do allow that -- they do not wake up threads that started waiting on the condition variable <em>after</em> the last <code>pthread_cond_broadcast()</code>.</p> <p>If we can rely on POSIX condition variable wakeup semantics, it means the above barrier implementation should work reliably, including in the case where threads arrive at the barrier (for the next iteration), even before all threads (from the previous iteration) have left the barrier.</p> <p>(Note that the known <em>"spurious wakeups"</em> issue only affects <code>pthread_cond_signal()</code>; i.e. when calling <code>pthread_cond_signal()</code> more than one thread may be woken up. Here, we wake up all threads using <code>pthread_cond_broadcast()</code>. We rely on it only waking current waiters, and not any future waiters.)</p> <hr> <p>Here is a POSIX.1-2001 implementation for suspending and resuming threads asynchronously, without any co-operation from the target thread(s).</p> <p>This uses two signals, one for suspending a thread, and another for resuming it. For maximum compatibility, I did not use GNU C extensions or POSIX.1b realtime signals. Both signals save and restore <code>errno</code>, so that the impact to the suspended threads would be minimal.</p> <p>Note, however, that the functions listed in <a href="http://man7.org/linux/man-pages/man7/signal.7.html" rel="nofollow">man 7 signal</a>, <em>"Interruption of system calls and library functions by signal handlers"</em> section, after the <em>"The following interfaces are never restarted after being interrupted by a signal handler"</em> paragraph, will return <code>errno==EINTR</code> when suspended/resumed. This means you will have to use the traditional <code>do { result = FUNCTION(...); } while (result == -1 &amp;&amp; errno == EINTR);</code> loop, instead of just <code>result = FUNCTION(...);</code>.</p> <p>The <code>suspend_threads()</code> and <code>resume_threads()</code> calls are not synchronous. The threads will be suspended/resumed either before, or sometime after, the function calls return. Also, suspend and resume signals sent from outside the process itself <em>may</em> affect the threads; it depends on if the kernel uses one of the target threads to deliver such signals. (This approach cannot ignore signals sent by other processes.)</p> <p>Testing indicates that in practice, this suspend/resume functionality is quite reliable, assuming no outside interference (by sending signals caught by the target threads from another process). However, it is not very robust, and there are very few guarantees on its operation, but it might suffice for some implementations.</p> <p><strong>suspend-resume.h</strong>:</p> <pre><code>#ifndef SUSPEND_RESUME_H #define SUSPEND_RESUME_H #if !defined(_POSIX_C_SOURCE) &amp;&amp; !defined(POSIX_SOURCE) #error This requires POSIX support (define _POSIX_C_SOURCE). #endif #include &lt;signal.h&gt; #include &lt;errno.h&gt; #include &lt;pthread.h&gt; #define SUSPEND_SIGNAL SIGUSR1 #define RESUME_SIGNAL SIGUSR2 /* Resume signal handler. */ static void resume_handler(int signum, siginfo_t *info, void *context) { /* The delivery of the resume signal is the key point. * The actual signal handler does nothing. */ return; } /* Suspend signal handler. */ static void suspend_handler(int signum, siginfo_t *info, void *context) { sigset_t resumeset; int saved_errno; if (!info || info-&gt;si_signo != SUSPEND_SIGNAL) return; /* Save errno to keep it unchanged in the interrupted thread. */ saved_errno = errno; /* Block until suspend or resume signal received. */ sigfillset(&amp;resumeset); sigdelset(&amp;resumeset, SUSPEND_SIGNAL); sigdelset(&amp;resumeset, RESUME_SIGNAL); sigsuspend(&amp;resumeset); /* Restore errno. */ errno = saved_errno; } /* Install signal handlers. */ static int init_suspend_resume(void) { struct sigaction act; sigemptyset(&amp;act.sa_mask); sigaddset(&amp;act.sa_mask, SUSPEND_SIGNAL); sigaddset(&amp;act.sa_mask, RESUME_SIGNAL); act.sa_flags = SA_RESTART | SA_SIGINFO; act.sa_sigaction = resume_handler; if (sigaction(RESUME_SIGNAL, &amp;act, NULL)) return errno; act.sa_sigaction = suspend_handler; if (sigaction(SUSPEND_SIGNAL, &amp;act, NULL)) return errno; return 0; } /* Suspend one or more threads. */ static int suspend_threads(const pthread_t *const identifier, const int count) { int i, result, retval = 0; if (!identifier || count &lt; 1) return errno = EINVAL; for (i = 0; i &lt; count; i++) { result = pthread_kill(identifier[i], SUSPEND_SIGNAL); if (result &amp;&amp; !retval) retval = result; } return errno = retval; } /* Resume one or more threads. */ static int resume_threads(const pthread_t *const identifier, const int count) { int i, result, retval = 0; if (!identifier || count &lt; 1) return errno = EINVAL; for (i = 0; i &lt; count; i++) { result = pthread_kill(identifier[i], RESUME_SIGNAL); if (result &amp;&amp; !retval) retval = result; } return errno = retval; } #endif /* SUSPEND_RESUME_H */ </code></pre> <hr> <p>Questions?</p>