MySQL Internals Manual  /  ...  /  A Typical Synchronization Pattern

23.6.4 A Typical Synchronization Pattern

There are quite a few places in MySQL, where we use a synchronization pattern like this:

pthread_mutex_lock(&mutex);
   thd->enter_cond(&condition_variable, &mutex, new_message);
 #if defined(ENABLE_DEBUG_SYNC)
   if (!thd->killed && !end_of_wait_condition)
     DEBUG_SYNC(thd, "sync_point_name");
 #endif
   while (!thd->killed && !end_of_wait_condition)
     pthread_cond_wait(&condition_variable, &mutex);
   thd->exit_cond(old_message);

Here some explanations:

thd->enter_cond() is used to register the condition variable and the mutex in thd->mysys_var. This is done to allow the thread to be interrupted (killed) from its sleep. Another thread can find the condition variable to signal and mutex to use for synchronization in this thread's THD::mysys_var.

thd->enter_cond() requires the mutex to be acquired in advance.

thd->exit_cond() unregisters the condition variable and mutex and releases the mutex.

If you want to have a Debug Sync point with the wait, please place it behind enter_cond(). Only then you can safely decide, if the wait will be taken. Also you will have THD::proc_info correct when the sync point emits a signal. DEBUG_SYNC sets its own proc_info, but restores the previous one before releasing its internal mutex. As soon as another thread sees the signal, it does also see the proc_info from before entering the sync point. In this case it will be "new_message", which is associated with the wait that is to be synchronized.

In the example above, the wait condition is repeated before the sync point. This is done to skip the sync point, if no wait takes place. The sync point is before the loop (not inside the loop) to have it hit once only. It is possible that the condition variable is signaled multiple times without the wait condition to be true.

A bit off-topic: At some places, the loop is taken around the whole synchronization pattern:

while (!thd->killed && !end_of_wait_condition)
   {
     pthread_mutex_lock(&mutex);
     thd->enter_cond(&condition_variable, &mutex, new_message);
     if (!thd->killed [&& !end_of_wait_condition])
   {
     [DEBUG_SYNC(thd, "sync_point_name");]
     pthread_cond_wait(&condition_variable, &mutex);
   }
     thd->exit_cond(old_message);
}

Note that it is important to repeat the test for thd->killed after enter_cond(). Otherwise the killing thread may kill this thread after it tested thd->killed in the loop condition and before it registered the condition variable and mutex in enter_cond(). In this case, the killing thread does not know that this thread is going to wait on a condition variable. It would just set THD::killed. But if we would not test it again, we would go asleep though we are killed. If the killing thread would kill us when we are after the second test, but still before sleeping, we hold the mutex, which is registered in mysys_var. The killing thread would try to acquire the mutex before signaling the condition variable. Since the mutex is only released implicitly in pthread_cond_wait(), the signaling happens at the right place. We have a safe synchronization.


User Comments
Sign Up Login You must be logged in to post a comment.