当前位置: 代码迷 >> 综合 >> POSIX thread(pthread) (二)
  详细解决方案

POSIX thread(pthread) (二)

热度:83   发布时间:2023-12-10 12:06:23.0

原文地址:http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html 

线程的同步

pthread提供三种同步的机制:
  • mutexs 互斥锁,阻止其他线程来访问变量,这可以保证只有这个线程能访问这个变量
  • joins 使一个线程等待另一个线程执行完毕
  • pthread_cond_t 条件变量


互斥:

互斥经常用于多个线程访问同一快内存区域造成数据的不一致,或者防止一些操作都需要一块内存从而产生竞争。竞争经常发生在2个或者多个线程操作同一快内存的时候, 而结果却希望按照调用的先后顺序来计算。互斥用来保证按顺序访问共享的内存。任何时候当一个全局的资源被多个线程访问的时候都应该加锁,锁可以保护资源不被别的线程访问。锁只能应用于线程当中,不然信号量就不起作用了。
例:
Without Mutex With Mutex
int counter=0;/* Function C */
void functionC()
{counter++}
/* Note scope of variable and mutex are the same */
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int counter=0;/* Function C */
void functionC()
{pthread_mutex_lock( &mutex1 );counter++pthread_mutex_unlock( &mutex1 );
}
Possible execution sequence
Thread 1 Thread 2 Thread 1 Thread 2
counter = 0 counter = 0 counter = 0 counter = 0
counter = 1 counter = 1 counter = 1 Thread 2 locked out.
Thread 1 has exclusive use of variable counter
      counter = 2

第一种没有互斥的情况假如寄存器读取和保存了这个自增的变量counter的时机不巧,有可能导致第一个线程写入的值被第二个线程写入的值覆盖,也有可能第二个线程先写入值,被第一个线程覆盖了。第二种有互斥的情况是当线程访问到自增变量counter后会锁住这个值,直到执行完毕,然后解开锁让其他线程访问。

Sequence Thread 1 Thread 2
1 counter = 0 counter=0
2 Thread 1 locked out.
Thread 2 has exclusive use of variable counter
counter = 1
3 counter = 2  


例 mtex1.c:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>void *functionC();
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int  counter = 0;main()
{int rc1, rc2;pthread_t thread1, thread2;/* Create independent threads each of which will execute functionC */if( (rc1=pthread_create( &thread1, NULL, &functionC, NULL)) ){printf("Thread creation failed: %d\n", rc1);}if( (rc2=pthread_create( &thread2, NULL, &functionC, NULL)) ){printf("Thread creation failed: %d\n", rc2);}/* Wait till threads are complete before main continues. Unless we  *//* wait we run the risk of executing an exit which will terminate   *//* the process and all threads before the threads have completed.   */pthread_join( thread1, NULL);pthread_join( thread2, NULL); exit(EXIT_SUCCESS);
}void *functionC()
{pthread_mutex_lock( &mutex1 );counter++;printf("Counter value: %d\n",counter);pthread_mutex_unlock( &mutex1 );
}
编译: cc -pthread mutex1.c (or cc -lpthread mutex1.c 老版本的GNU编译器) 
运行: ./a.out 
Results:
Counter value: 1
Counter value: 2
当一个线程尝试访问一个已经上锁的变量时,这个线程会被阻塞。当一个线程结束的时候,互斥锁不会自动解开

联结

联结的作用是等待另一个线程执行玩后在执行,一个线程的调用有时需要几个线程执行完后的结果,这时候就需要联结。
例 join1.c:
#include <stdio.h>
#include <pthread.h>#define NTHREADS 10
void *thread_function(void *);
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int  counter = 0;main()
{pthread_t thread_id[NTHREADS];int i, j;for(i=0; i < NTHREADS; i++){pthread_create( &thread_id[i], NULL, thread_function, NULL );}for(j=0; j < NTHREADS; j++){pthread_join( thread_id[j], NULL); }/* Now that all threads are complete I can print the final result.     *//* Without the join I could be printing a value before all the threads *//* have been completed.                                                */printf("Final counter value: %d\n", counter);
}void *thread_function(void *dummyPtr)
{printf("Thread number %ld\n", pthread_self());pthread_mutex_lock( &mutex1 );counter++;pthread_mutex_unlock( &mutex1 );
}


编译: cc -pthread join1.c (or cc -lpthread join1.c  老的GNU编译) 
运行: ./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

条件变量

条件变量的类型是pthread_cond_t,用于函数调用时的延后处理。这个条件变量的机制就是允许线程挂起,然后但条件满足的时候继续执行。条件变量必须和互斥变量一起使用,这样可以避免:一个线程在等待另一个线程,另一个线程标志了条件也在等待第一个线程触发信号,这样两个线程永远在等待互相执行完毕,所以引起了死锁。在条件变量和互斥锁之间并没有明显的区别,两个在程序中都可以使用。
条件变量的相关说明:
创建和销毁
     pthread_cond_init
    pthread_cond_t cond =PTHREAD_COND_INITIALIZER
    pthread_cond_destory
等待
    pthread_cond_wait 解锁互斥并等待条件被触发
    pthread_cond_timewait 设置等待的超时
    醒来
   pthread_cond_signal 使等待这个条件变量的线程继续执行
   pthread_cond_broadcast 所有因这个条件变量而阻塞的线程继续执行
例:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>pthread_mutex_t count_mutex     = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  condition_var   = PTHREAD_COND_INITIALIZER;void *functionCount1();
void *functionCount2();
int  count = 0;
#define COUNT_DONE  10
#define COUNT_HALT1  3
#define COUNT_HALT2  6main()
{pthread_t thread1, thread2;pthread_create( &thread1, NULL, &functionCount1, NULL);pthread_create( &thread2, NULL, &functionCount2, NULL);pthread_join( thread1, NULL);pthread_join( thread2, NULL);printf("Final count: %d\n",count);exit(EXIT_SUCCESS);
}// Write numbers 1-3 and 8-10 as permitted by functionCount2()void *functionCount1()
{for(;;){// Lock mutex and then wait for signal to relase mutexpthread_mutex_lock( &count_mutex );// Wait while functionCount2() operates on count// mutex unlocked if condition varialbe in functionCount2() signaled.pthread_cond_wait( &condition_var, &count_mutex );count++;printf("Counter value functionCount1: %d\n",count);pthread_mutex_unlock( &count_mutex );if(count >= COUNT_DONE) return(NULL);}
}// Write numbers 4-7void *functionCount2()
{for(;;){pthread_mutex_lock( &count_mutex );if( count < COUNT_HALT1 || count > COUNT_HALT2 ){// Condition of if statement has been met. // Signal to free waiting thread by freeing the mutex.// Note: functionCount1() is now permitted to modify "count".pthread_cond_signal( &condition_var );}else{count++;printf("Counter value functionCount2: %d\n",count);}pthread_mutex_unlock( &count_mutex );if(count >= COUNT_DONE) return(NULL);}}
编译: cc -pthread cond1.c (or cc -lpthread cond1.c 老版本的GNU编译器) 
运行: ./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

注意:但count的值在 COUNT_HALT1和COUNT_HALT2之间时function1()就停止执行了。唯一可以肯定的是但count的值在 COUNT_HALT1和COUNT_HALT2之间function2()会增加count的值,其它的情况都是随机的。
逻辑条件if和while用来保证在等待的时候“信号”可以被执行。糟糕的逻辑会引起死锁。
注意:这个例子中的竞争条件是count,他在while循环种不能被锁住,否则会引起死锁。
  相关解决方案