线程同步
目录
1. 线程同步概述线程同步定义线程同步,指的是控制多线程间的相对执行顺序,从而在线程间正确、有序地共享数据,以下为线程同步常见使用场合。
线程同步方法在实际项目中,经常使用的线程同步方法主要分为三种:
本节内容只介绍互斥锁和条件变量,Posix信号量后续在Posix IPC专题中介绍。 2. 互斥锁互斥锁概念互斥锁用于确保同一时间只有一个线程访问共享数据,使用方法为:
对互斥锁加锁后,任何其他试图再次对其加锁的线程都会被阻塞,直到当前线程释放该互斥锁,解锁时所有阻塞线程都会变成可运行状态,但究竟哪个先运行,这一点是不确定的。 互斥锁基本API初始化与销毁互斥锁是用
互斥锁使用完以后,可以调用 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //两个函数的返回值:成功返回0,失败返回错误编号 int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr); int pthread_mutex_destroy(pthread_mutex_t *mutex); 其中,pthread_mutex_init的第二个参数attr用于设置互斥锁的属性,如果要使用默认属性,只需把attr设为NULL。 上锁与解锁//两个函数的返回值:成功返回0,失败返回错误编号 int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex); 对互斥锁上锁,需要调用 两个特殊的上锁函数尝试上锁//成功返回0,失败返回错误编号 int pthread_mutex_trylock(pthread_mutex_t *mutex); 如果不希望调用线程阻塞,可以使用
限时上锁//成功返回0,失败返回错误编号 int pthread_mutex_timedlock(pthread_mutex_t *mutex,const struct timespec *time);
关于第二个参数time,有两点需要注意:
示例代码/* * 测试使用上述4个加锁函数 */ #include <pthread.h> #include <time.h> #include <errno.h> #include <stdio.h> pthread_mutex_t mutex1; pthread_mutex_t mutex2; pthread_mutex_t mutex3; void *thread1_start(void *arg) { pthread_mutex_lock(&mutex1); printf("thread1 has locked mutex1n"); sleep(2); //保证thread2执行时mutex1还未解锁 pthread_mutex_unlock(&mutex1); } void *thread2_start(void *arg) { if (pthread_mutex_trylock(&mutex2) == 0) printf("thread2 trylock mutex2 sucessn"); if (pthread_mutex_trylock(&mutex1) == EBUSY) printf("thread2 trylock mutex1 failedn"); pthread_mutex_unlock(&mutex2); } void *thread3_start(void *arg) { struct timespec time; struct tm *tmp_time; char s[64]; int err; pthread_mutex_lock(&mutex3); printf("thread3 has locked mutex3n"); /*获取当前时间,并转化为本地时间打印*/ clock_gettime(CLOCK_REALTIME,&time); tmp_time = localtime(&time.tv_sec); strftime(s,sizeof(s),"%r",tmp_time); printf("current time is %sn",s); /*设置time = 当前时间 + 等待时间10S*/ time.tv_sec = time.tv_sec + 10; /*mutex3已上锁,这里会阻塞*/ if (pthread_mutex_timedlock(&mutex3,&time) == ETIMEDOUT) printf("pthread_mutex_timedlock mutex3 timeoutn"); /*再次获取当前时间,并转化为本地时间打印*/ clock_gettime(CLOCK_REALTIME,tmp_time); printf("the time is now %sn",s); pthread_mutex_unlock(&mutex3); } int main() { pthread_t tid1; pthread_t tid2; pthread_t tid3; /*测试pthread_mutex_lock和pthread_mutex_trylock*/ pthread_mutex_init(&mutex1,NULL); pthread_mutex_init(&mutex2,NULL); pthread_create(&tid1,NULL,thread1_start,NULL); pthread_create(&tid2,thread2_start,NULL); if (pthread_join(tid1,NULL) == 0) { pthread_mutex_destroy(&mutex1); } if (pthread_join(tid2,NULL) == 0) { pthread_mutex_destroy(&mutex2); } /*测试pthread_mutex_timedlock*/ pthread_mutex_init(&mutex3,NULL); pthread_create(&tid3,thread3_start,NULL); if (pthread_join(tid3,NULL) == 0) { pthread_mutex_destroy(&mutex3); } return 0; } 3. 避免死锁线程的死锁概念线程间死锁,指的是线程间相互等待临界资源而造成彼此无法继续执行的现象。 产生死锁的四个必要条件
直观上看,循环等待条件似乎和死锁的定义一样,其实不然,因为死锁定义中的要求更为严格:
如何避免死锁
4. 条件变量条件变量概念
条件变量基本API初始化与销毁条件变量是用
条件变量使用完以后,可以调用 pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //两个函数的返回值:成功返回0,失败返回错误编号 int pthread_cond_init(pthread_cond_t *cond,const pthread_condattr_t *attr); int pthread_cond_destroy(pthread_cond_t *cond); 其中,pthread_cond_init的第二个参数attr用于设置条件变量的属性,如果要使用默认属性,只需把attr设为NULL。 等待条件满足//两个函数的返回值:成功返回0,失败返回错误编号 int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex); int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex,const struct timespec *timeout); 可以调用
注意:当条件满足从pthread_cond_wait和pthread_cond_timedwait返回时,调用线程必须重新计算条件,因为另一个线程可能已经在运行并改变了条件。 给线程发信号有两个函数可以用于通知线程条件已经满足:
//两个函数的返回值:成功返回0,失败返回错误编号 int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); 在调用上面两个函数时,我们说这是在给线程发信号,注意,一定要先获取互斥锁,再改变条件,然后给线程发信号,最后再对互斥锁解锁。 示例代码/* * 结合使用条件变量和互斥锁进行线程同步 */ #include <pthread.h> #include <stdio.h> static pthread_cond_t cond; static pthread_mutex_t mutex; static int cond_value; static int quit; void *thread_signal(void *arg) { while (!quit) { pthread_mutex_lock(&mutex); cond_value++; //改变条件,使条件满足 pthread_cond_signal(&cond); //给线程发信号 printf("signal send,cond_value: %dn",cond_value); pthread_mutex_unlock(&mutex); sleep(1); } } void *thread_wait(void *arg) { while (!quit) { pthread_mutex_lock(&mutex); /*通过while (cond is true)来保证从pthread_cond_wait成功返回时,调用线程会重新检查条件*/ while (cond_value == 0) pthread_cond_wait(&cond,&mutex); cond_value--; printf("signal recv,cond_value); pthread_mutex_unlock(&mutex); sleep(1); } } int main() { pthread_t tid1; pthread_t tid2; pthread_cond_init(&cond,NULL); pthread_mutex_init(&mutex,thread_signal,thread_wait,NULL); sleep(5); quit = 1; pthread_join(tid1,NULL); pthread_join(tid2,NULL); pthread_cond_destroy(&cond); pthread_mutex_destroy(&mutex); return 0; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |