Книга: Programming with POSIX® Threads

3.3.1 Creating and destroying a condition variable

3.3.1 Creating and destroying a condition variable

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int pthread_cond_init (pthread_cond_t *cond,

pthread_condattr_t *condattr);

int pthread_cond_destroy (pthread_cond_t *cond);

A condition variable is represented in your program by a variable of type pthread_cond_t. You should never make a copy of a condition variable, because the result of using a copied condition variable is undefined. It would be like telephoning a disconnected number and expecting an answer. One thread could, for example, wait on one copy of the condition variable, while another thread signaled or broadcast the other copy of the condition variable—the waiting thread would not be awakened. You can, however, freely pass pointers to a condition variable so that various functions and threads can use it for synchronization.

Most of the time you'll probably declare condition variables using the extern or static storage class at file scope, that is, outside of any function. They should have normal (extern) storage class if they are used by other files, or static storage class if used only within the file that declares the variable. When you declare a static condition variable that has default attributes, you should use the PTHREAD_COND_INITIALIZER initialization macro, as shown in the following example, cond_static.c.

? cond_static.c

1 #include <pthread.h>
2 #include "errors.h"
3
4 /*
5 * Declare a structure, with a mutex and condition variable,
6 * statically initialized. This is the same as using
7 * pthread_mutex_init and pthread_cond_init, with the default
8 * attributes.
9 */
10 typedef struct my_struct_tag {
11  pthread_mutex_t mutex; /* Protects access to value */
12  pthread_cond_t cond; /* Signals change to value */
13  int value; /* Access protected by mutex */
14 } my_struct_t;

15
16 my_struct_t data = {
17  PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0};

18
19 int main (int argc, char *argv[])
20 {
21  return 0 ;
22 }

Condition variables and their predicates are "linked"—for best results, treat them that way!

When you declare a condition variable, remember that a condition variable and the associated predicate are "locked together." You may save yourself (or your successor) some confusion by always declaring the condition variable and predicate together, if possible. I recommend that you try to encapsulate a set of invariants and predicates with its mutex and one or more condition variables as members in a structure, and carefully document the association.

Sometimes you cannot initialize a condition variable statically; for example, when you use malloc to create a structure that contains a condition variable. Then you will need to call pthread_cond_init to initialize the condition variable dynamically, as shown in the following example, cond_dynamic.c. You can also dynamically initialize condition variables that you declare statically—but you must ensure that each condition variable is initialized before it is used, and that each is initialized only once. You may initialize it before creating any threads, for example, or by using pthread_once (Section 5.1). If you need to initialize a condition variable with nondefault attributes, you must use dynamic initialization (see Section 5.2.2).

cond_dynamic.c

1 #include <pthread.h>
2 #include "errors.h" 3
4 /*
5 * Define a structure, with a mutex and condition variable.
6 */
7 typedef struct my_struct_tag {
8 pthread_mutex_t mutex; /* Protects access to value */
9 pthread_cond_t cond; /* Signals change to value */
10 int value; /* Access protected by mutex */
11 } my_struct_t;

12
13 int main (int argc, char *argv[])
14 {
15 my_struct_t *data;
16 int status;

17
18 data = malloc (sizeof (my_struct_t));
19 if (data == NULL)
20  errno_abort ("Allocate structure");
21 status = pthread_mutex_init (&data->mutex, NULL);
22 if (status != 0)
23  err_abort (status, "Init mutex");
24 status = pthread_cond_init (&data->cond, NULL);
25 if (status != 0)
26 err_abort (status, "Init condition");
27 status = pthread_cond_destroy (&data->cond);
28 if (status != 0)
29  err_abort (status, "Destroy condition");
30 status = pthread_mutex_destroy (&data->mutex);
31 if (status != 0)
32  err_abort (status, "Destroy mutex");
33 (void)free (data);
34 return status;
35 }

When you dynamically initialize a condition variable, you should destroy the condition variable when you no longer need it, by calling pthread_cond_destroy. You do not need to destroy a condition variable that was statically initialized using the PTHREAD_COND_INITIALIZER macro.

It is safe to destroy a condition variable when you know that no threads can be blocked on the condition variable, and no additional threads will try to wait on, signal, or broadcast the condition variable. The best way to determine this is usually within a thread that has just successfully broadcast to unblock all waiters, when program logic ensures that no threads will try to use the condition variable later.

When a thread removes a structure containing a condition variable from a list, for example, and then broadcasts to awaken any waiters, it is safe (and also a very good idea) to destroy the condition variable before freeing the storage that the condition variable occupies. The awakened threads should check their wait predicate when they resume, so you must make sure that you don't free resources required for the predicate before they've done so—this may require additional synchronization.

Оглавление книги


Генерация: 0.122. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз