1、/ 第四天 线程同步 /多线程同步问题线程共享进程的资源和地址空间任何线程对系统资源的操作都会给其他线程带来影响线程共享进程的资源和地址空间,对这些资源进行操作时,必须考虑线程间同步与互斥问题三种线程同步机制互斥锁信号量条件变量互斥锁用简单的加锁方法控制对共享资源的原子操作只有两种状态: 上锁、解锁互斥锁:更适合同时可用的资源是惟一的情况可把互斥锁看作某种意义上的全局变量在同一时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程能够对共享资源进行操作若其他线程希望上锁一个已经被上锁的互斥锁,则该线程就会挂起,直到上锁的线程释放掉互斥锁为止互斥锁保证让每个线程对共享资源按顺序进行原子操作互斥锁分
2、类区别在于其他未占有互斥锁的线程在希望得到互斥锁时是否需要阻塞等待快速互斥锁?调用线程会阻塞直至拥有互斥锁的线程解锁为止?默认为快速互斥锁检错互斥锁?为快速互斥锁的非阻塞版本,它会立即返回并返回一个错误信息互斥锁主要包括下面的基本函数:互斥锁初始化:pthread_mutex_init()互斥锁上锁:pthread_mutex_lock()互斥锁判断上锁:pthread_mutex_trylock()互斥锁解锁:pthread_mutex_unlock()消除互斥锁:pthread_mutex_destroy() 3.线程的互斥作用是用于互斥(即运行当前的不能运行另一个)实现线程间同时访问共享
3、的资源,避免同时操作pthread_mutex_t /互斥量(锁)类型,用来定义互斥量对互斥量做初始化int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);restrict mutex:互斥量的地址,互斥量通过这个函数获取初始值restrict attr: 属性,通常为 NULL互斥锁与解锁 int pthread_mutex_lock(pthread_mutex_t *mutex); /加锁,int pthread_mutex_unlock(pthrea
4、d_mutex_t *mutex);/解锁mutex:为互斥量的地址例:pthread_mutex_t mutex;/定义互斥量char buf1024;void *thr_fn1(void *arg)int i=0;while(1)pthread_mutex_lock(sprintf(buf,“thr_fn1 -%dn“,i+);printf(“%sn“,buf);sleep(8);pthread_mutex_unlock(usleep(50000);return (void*)23;/用 return 跳出线程void *thr_fn2(void *arg)int i=0;while(1)
5、pthread_mutex_lock(sprintf(buf,“thr_fn2 -%dn“,i+);printf(“%sn“,buf);pthread_mutex_unlock(usleep(50000);pthread_exit(void*)24);int main(int argc,char *argv)pthread_mutex_init(void *tret;pthread_t tid1,tid2,tid3;pthread_create(pthread_create(pthread_join(tid2,pthread_join(tid1,return 0;4.线程的同步(条件变量)同步
6、:就是线程待某件事件的发生,当等待事件发生时,被等待的线程和事件一起继续执行待待的线程在事件未发生时则挂起。 pthread_cond_t 是线程同的的条件变量1)对变量进行初始化int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);restrict cond:条件变量 restrict attr:属性,通常设为 NULL2)线程同步等待函数 int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_m
7、utex_t *restrict mutex);cond:线程同步的条件变量mutex:线程互斥量作用:是等待条件的发生,被调用后线程自动阻塞,直到相应的条件被设置。在等待时,不占用 CPU 时间在等待的同时直接解锁,在接到信号后马上加锁3)发送条件信号的函数int pthread_cond_signal(pthread_cond_t *cond);cond:线程同步的条件例:在某种情况下,激活另一个线程pthread_mutex_t mutex;/定义互斥量pthread_cond_t cond; /定义同步条件int count;void *thr_fn1(void *arg)while(
8、1) pthread_mutex_lock(if (count 用 sem_t 类型来声明一个型号量。1.初始化信号量int sem_init(sem_t *sem, int pshared, unsigned int value)sem 信号量pshared 共享方式 ,表示这个信号量只是当前进程中的型号量,如果不为,这个信号量可能可以在两个进程中共享。value 信号量初始值2.P 操作,减少信号量sem_wait(sem_t *sem)sem_trywait(sem_t *sem); 函数用于接受信号,当 sem0 时就能接受到信号,然后将 sem-;两个函数都是在信号量大于零时将信号量
9、的值减一区别: 若信号量小于零时, sem_wait()将会阻塞线程 ,sem_trywait()则会立即返回3.V 操作,增加信号量sem_post(sem_t *sem)将信号量的值加一同时发出信号来唤醒等待的线程4.解除信号量sem_destroy(sem_t *sem)函数用于解除信号量。5.获取信号量的值sem_getvalue(set_t *sem)例:#include #include #include sem_t sem1, sem2; void *thread1(void *arg) sem_wait( printf(“hello n“); sem_post( void *t
10、hread2(void *arg) sem_wait( printf(“world!n“); int main() pthread_t t1, t2; sem_init( sem_init( pthread_create( pthread_create( pthread_join(t1,NULL); pthread_join(t2,NULL); sem_destroy( sem_destroy( return 0; 在多进程编程中,进程 A 需要暂时阻塞,等待另一进程 B 访问资源,当 B 处理结束后,进程 A 再继续执行。这种情况下用到进程同步。信号量实现的是一种类似计数器的功能,用来实现进
11、程间的互斥及同步信号量的数据结构:struct semid_dsstruct ipc-perm sem_perm; /许可权限time_t sem_otime; /最后一次操作时间time_t sem_ctime; /最后一次调用 semctl 时间unsigned long sem_nsems; /信号量个数;PV 操作主要用于线程间的同步和互斥互斥,几个线程只设置一个信号量 sem同步,会设置多个信号量,安排不同初值来实现它们之间的顺序执行- 信号量 sem =0 | / | sem0| P 操作/ V 操作 |sem -1 sem+1| | | |进程阻塞|- 阻塞进程队列 #inclu
12、de #include #include #define THREAD_NUM 3#define REPEAT_TIMES 5#define DELAY 4sem_t semTHREAD_NUM;void *thrd_func(void *arg)int thrd_num=(void*)arg; / 参数 noint delay_time,count; / 带有阻塞的 p 操作sem_wait(printf(“Thread %d is starting.n“,thrd_num);for(count=0;countREPEAT_TIMES;count+) printf(“/-n“); sleep
13、(delay_time); printf(“Thread %d is exiting.n“,thrd_num);/ 对前一个信号量进行 V 操作/ 由于只有最后一个信号量初始化为 1,其余均为 0/ 故线程执行的顺序将为逆序sem_post(pthread_exit(NULL); / 线程主动结束 int main()pthread_t threadTHREAD_NUM;int no;void *tret;srand(int)time(0); / 初始化 THREAD_NUM-1 个信号量,均初始化为 0for(no=0;noTHREAD_NUM-1;no+)sem_init(/ sem2信号
14、量初始化为 1,即 sem 数组中最后一个信号量sem_init(/ 创建 THREAD_NUM 个线程,入口函数均为 thrd_func,参数为(void*)nofor(no=0;noTHREAD_NUM;no+)if (pthread_create(exit(1); elseprintf(“Create thread %d success!n“,no);/ 逐个 join 掉 THREAD_NUM 个线程for(no=0;noTHREAD_NUM;no+)if (pthread_join(threadno,exit(1);elseprintf(“Join thread %d success!n“,no);/ 逐个取消信号量for(no=0;noTHREAD_NUM;no+)sem_destroy(return 0;