/* Now that all threads are complete I can print the final result. */
25
/* Without the join I could be printing a value before all the threads */
26
/* have been completed. */
27
28
printf("Final counter value: %d/n", counter);
29
}
30
31
void*thread_function(void*dummyPtr)
32
{
33
printf("Thread number %ld/n", pthread_self());
34
pthread_mutex_lock( &mutex1 );
35
counter++;
36
pthread_mutex_unlock( &mutex1 );
37
}
编译: cc -lpthread join1.c 运行: ./a.out 结果:
Thread number 1026
Thread number 2051
Thread number 3076
Thread number 4101
Thread number 5126
Thread number 6151
Thread number 7176
Thread number 8201
Thread number 9226
Thread number 10251
Final counter value: 10
printf("Counter value functionCount1: %d/n",count);
44
45
pthread_mutex_unlock( &count_mutex );
46
47
if(count >= COUNT_DONE) return(NULL);
48
}
49
}
50
51
// Write numbers 4-7
52
53
void*functionCount2()
54
{
55
for(;;)
56
{
57
pthread_mutex_lock( &count_mutex );
58
59
if( count < COUNT_HALT1 || count > COUNT_HALT2 )
60
{
61
// Condition of if statement has been met.
62
// Signal to free waiting thread by freeing the mutex.
63
// Note: functionCount1() is now permitted to modify "count".
64
pthread_cond_signal( &condition_var );
65
}
66
else
67
{
68
count++;
69
printf("Counter value functionCount2: %d/n",count);
70
}
71
72
pthread_mutex_unlock( &count_mutex );
73
74
if(count >= COUNT_DONE) return(NULL);
75
}
76
77
}
编译: cc -lpthread cond1.c 运行: ./a.out 结果:
Counter value functionCount1: 1
Counter value functionCount1: 2
Counter value functionCount1: 3
Counter value functionCount2: 4
Counter value functionCount2: 5
Counter value functionCount2: 6
Counter value functionCount2: 7
Counter value functionCount1: 8
Counter value functionCount1: 9
Counter value functionCount1: 10
Final count: 10
When this option is enabled, each thread may have its own scheduling properties. Scheduling attributes may be specified:
during thread creation
by dynamically by changing the attributes of a thread already created
by defining the effect of a mutex on the thread's scheduling when creating a mutex
by dynamically changing the scheduling of a thread during synchronization operations.
The threads library provides default values that are sufficient for most cases.
Thread Pitfalls:
Race conditions: While the code may appear on the screen in the order you wish the code to execute, threads are scheduled by the operating system and are executed at random. It cannot be assumed that threads are executed in the order they are created. They may also execute at different speeds. When threads are executing (racing to complete) they may give unexpected results (race condition). Mutexes and joins must be utilized to achieve a predictable execution order and outcome.
Thread safe code: The threaded routines must call functions which are "thread safe". This means that there are no static or global variables which other threads may clobber or read assuming single threaded operation. If static or global variables are used then mutexes must be applied or the functions must be re-written to avoid the use of these variables. In C, local variables are dynamically allocated on the stack. Therefore, any function that does not use static data or other shared resources is thread-safe. Thread-unsafe functions may be used by only one thread at a time in a program and the uniqueness of the thread must be ensured. Many non-reentrant functions return a pointer to static data. This can be avoided by returning dynamically allocated data or using caller-provided storage. An example of a non-thread safe function is strtok which is also not re-entrant. The "thread safe" version is the re-entrant version strtok_r.
Mutex Deadlock: This condition occurs when a mutex is applied but then not "unlocked". This causes program execution to halt indefinitely. It can also be caused by poor application of mutexes or joins. Be careful when applying two or more mutexes to a section of code. If the first pthread_mutex_lock is applied and the second pthread_mutex_lock fails due to another thread applying a mutex, the first mutex may eventually lock all other threads from accessing data including the thread which holds the second mutex. The threads may wait indefinitely for the resource to become free causing a deadlock. It is best to test and if failure occurs, free the resources and stall before retrying.
01
...
02
pthread_mutex_lock(&mutex_1);
03
while( pthread_mutex_trylock(&mutex_2) ) /* Test if already locked */
04
{
05
pthread_mutex_unlock(&mutex_1); /* Free resource to avoid deadlock */
06
...
07
/* stall here */
08
...
09
pthread_mutex_lock(&mutex_1);
10
}
11
count++;
12
pthread_mutex_unlock(&mutex_1);
13
pthread_mutex_unlock(&mutex_2);
14
...
The order of applying the mutex is also important. The following code segment illustrates a potential for deadlock:
If function1 acquires the first mutex and function2 acquires the second, all resources are tied up and locked.
Condition Variable Deadlock: The logic conditions (the "if" and "while" statements) must be chosen to insure that the "signal" is executed if the "wait" is ever processed.