多个线程共享相同的内存时,需要确保每个线程看到一致的数据视图。
1.互斥量
- #include<pthread.h>
- int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
- int pthread_mutex_destroy(pthread_mutex_t * mutex);
- //成功返回0,否则返回错误编号
- #include <pthread.h>
- int pthread_mutex_lock(pthread_mutex_t *mutex);
- int pthread_mutex_trylock(pthread_mutex)_t *mutex);
- int pthread_mutex_unlock(pthread_mutex_t *mutex);
- //如果成功返回0,否则返回错误编号。
- #include <stdio.h>
- #include <pthread.h>
- #include <malloc.h>
- #include <string.h>
- void* th_func(void* arg){
- int i;
- for(i=0; i<5; i++){
- printf("1\n");
- sleep(1);
- printf("2\n");
- }
- }
- int main(void){
- int ret;
- pthread_t tid1,tid2;
- ret = pthread_create(&tid1, NULL, th_func, NULL);
- if(ret != 0){
- printf("pthread_create:%s\n",strerror(ret));
- return -1;
- }
- ret = pthread_detach(tid1);
- if(ret != 0){
- printf("pthread_detach:%s\n",strerror(ret));
- return -1;
- }
- ret = pthread_create(&tid2, NULL, th_func, NULL);
- if(ret != 0){
- printf("pthread_create:%s\n",strerror(ret));
- return -1;
- }
- ret = pthread_detach(tid2);
- if(ret != 0){
- printf("pthread_detach:%s\n",strerror(ret));
- return -1;
- }
- sleep(15);
- return 0;
- }
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
2
- #include <stdio.h>
- #include <pthread.h>
- #include <malloc.h>
- #include <string.h>
- pthread_mutex_t *mutex;
- void* th_func(void* arg){
- int i;
- for(i=0; i<5; i++){
- pthread_mutex_lock(mutex);
- printf("1\n");
- sleep(1);
- printf("2\n");
- pthread_mutex_unlock(mutex);
- }
- }
- int main(void){
- int ret,result = 0;
- pthread_t tid1,tid2;
- mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
- if(mutex == NULL){
- perror("malloc");
- result = -1;
- goto FINALLY;
- }
- pthread_mutex_init(mutex,NULL);
- ret = pthread_create(&tid1, NULL, th_func, NULL);
- if(ret != 0){
- printf("pthread_create:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- ret = pthread_detach(tid1);
- if(ret != 0){
- printf("pthread_detach:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- ret = pthread_create(&tid2, NULL, th_func, NULL);
- if(ret != 0){
- printf("pthread_create:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- ret = pthread_detach(tid2);
- if(ret != 0){
- printf("pthread_detach:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- sleep(15);
- FINALLY:
- if(mutex != NULL){
- pthread_mutex_destroy(mutex);
- free(mutex);
- }
- return result;
- }
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
1
2
2.避免死锁
3.读写锁
- #include <pthread.h>
- int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
- int pthread_rwlock_destory(pthread_rwlock_t *rwlock);
- //若成功返回0,否则返回错误编号。
- #include<pthread.h>
- int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
- int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
- int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
- //成功则返回0,否则返回错误编号。
- #include <pthread.h>
- int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
- int pthread_rwlock_tryrwlock(pthread_rwlock_t *rwlock);
- //成功返回0,否则返回错误编号。
- #include <stdio.h>
- #include <pthread.h>
- #include <malloc.h>
- #include <string.h>
- pthread_rwlock_t *rwlock;
- int gi=0;
- void* th_func1(void* arg){
- int i;
- for(i=0; i<5; i++){
- pthread_rwlock_rdlock(rwlock);
- printf("start1:%d\n",gi);
- sleep(1);
- printf("end1:%d\n",gi);
- pthread_rwlock_unlock(rwlock);
- sleep(1);
- }
- }
- void* th_func2(void* arg){
- int i;
- for(i=0; i<5; i++){
- pthread_rwlock_rdlock(rwlock);
- printf("start2:%d\n",gi);
- sleep(1);
- printf("end2:%d\n",gi);
- pthread_rwlock_unlock(rwlock);
- sleep(1);
- }
- }
- void* th_func3(void* arg){
- int i;
- for(i=0; i<5; i++){
- pthread_rwlock_wrlock(rwlock);
- gi++;
- sleep(1);
- pthread_rwlock_unlock(rwlock);
- sleep(1);
- }
- }
- int main(void){
- int ret,result = 0;
- pthread_t tid1,tid2,tid3;
- rwlock = (pthread_rwlock_t*)malloc(sizeof(pthread_rwlock_t));
- if(rwlock == NULL){
- perror("malloc");
- goto FINALLY;
- }
- ret = pthread_create(&tid1, NULL, th_func1, NULL);
- if(ret != 0){
- printf("pthread_create:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- ret = pthread_detach(tid1);
- if(ret != 0){
- printf("pthread_detach:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- ret = pthread_create(&tid2, NULL, th_func2, NULL);
- if(ret != 0){
- printf("pthread_create:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- ret = pthread_detach(tid2);
- if(ret != 0){
- printf("pthread_detach:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- ret = pthread_create(&tid3, NULL, th_func3, NULL);
- if(ret != 0){
- printf("pthread_create:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- ret = pthread_detach(tid3);
- if(ret != 0){
- printf("pthread_detach:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- sleep(15);
- FINALLY:
- if(rwlock != NULL){
- pthread_rwlock_destroy(rwlock);
- free(rwlock);
- }
- return result;
- }
start1:1
end2:1
end1:1
start2:2
start1:2
end2:2
end1:2
start2:3
start1:3
end2:3
end1:3
start2:4
start1:4
end2:4
end1:4
start2:5
start1:5
end2:5
end1:5
一次循环中start和end中的值都是一样的。
- #include <stdio.h>
- #include <pthread.h>
- #include <malloc.h>
- #include <string.h>
- int gi=0;
- void* th_func1(void* arg){
- int i;
- for(i=0; i<5; i++){
- printf("start1:%d\n",gi);
- sleep(1);
- printf("end1:%d\n",gi);
- sleep(1);
- }
- }
- void* th_func2(void* arg){
- int i;
- for(i=0; i<5; i++){
- printf("start2:%d\n",gi);
- sleep(1);
- printf("end2:%d\n",gi);
- sleep(1);
- }
- }
- void* th_func3(void* arg){
- int i;
- for(i=0; i<5; i++){
- gi++;
- sleep(1);
- }
- }
- int main(void){
- int ret,result = 0;
- pthread_t tid1,tid2,tid3;
- ret = pthread_create(&tid1, NULL, th_func1, NULL);
- if(ret != 0){
- printf("pthread_create:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- ret = pthread_detach(tid1);
- if(ret != 0){
- printf("pthread_detach:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- ret = pthread_create(&tid2, NULL, th_func2, NULL);
- if(ret != 0){
- printf("pthread_create:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- ret = pthread_detach(tid2);
- if(ret != 0){
- printf("pthread_detach:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- ret = pthread_create(&tid3, NULL, th_func3, NULL);
- if(ret != 0){
- printf("pthread_create:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- ret = pthread_detach(tid3);
- if(ret != 0){
- printf("pthread_detach:%s\n",strerror(ret));
- result = -1;
- goto FINALLY;
- }
- sleep(15);
- FINALLY:
- return result;
- }
start1:1
end2:2
end1:2
start2:3
start1:3
end2:4
end1:4
start2:5
start1:5
end2:5
end1:5
start2:5
start1:5
end2:5
end1:5
start2:5
start1:5
end2:5
end1:5
4.条件变量
- #include<pthread.h>
- int pthread_cond_init(pthread_cond_t *restrict cond, pthread_condattr_t *restrict attr);
- int pthread_cond_destroy(pthread_cond_t *cond);
- //成功则返回0,否则返回错误编号。
- #include<pthread.h>
- int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
- //成功返回0,否则返回错误编号。
- #include<pthread.h>
- int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex,
- const struct timespec *restrict timeout);
- //成功返回0,否则返回错误编号。
- struct timespec{
- time_t tv_sec; //秒数
- long tv_nsec; //纳秒
- }
- #include <pthread.h>
- int pthread_cond_siganl(pthread_cond_t *cond);
- int pthread_cond_broadcast(pthread_cond_t *cond);
- //成功则返回0,否则返回错误编号。
- #include <stdio.h>
- #include <pthread.h>
- #include <string.h>
- pthread_cond_t qready = PTHREAD_COND_INITIALIZER;
- pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;
- int gi=0;
- void* substract(void* arg){
- int i;
- for(i=0; i<5; i++){
- pthread_mutex_lock(&qlock);
- while(gi == 0)
- pthread_cond_wait(&qready, &qlock);
- printf("before substract gi:%d.\n",gi);
- gi--;
- printf("after substract gi:%d.\n",gi);
- pthread_mutex_unlock(&qlock);
- }
- }
- void* add(void* arg){
- int i;
- for(i=0; i<5; i++){
- pthread_mutex_lock(&qlock);
- printf("before add gi:%d.\n",gi);
- gi++;
- printf("after add gi:%d.\n",gi);
- pthread_mutex_unlock(&qlock);
- pthread_cond_signal(&qready);
- }
- }
- int main(void){
- int ret;
- pthread_t tid1,tid2;
- ret = pthread_create(&tid1, NULL, substract, NULL);
- if(ret != 0){
- printf("pthread_create:%s",strerror(ret));
- return -1;
- }
- <span style="white-space:pre"> </span>sleep(1);
- ret = pthread_create(&tid2, NULL, add, NULL);
- if(ret != 0){
- printf("pthread_create:%s",strerror(ret));
- return -1;
- }
- ret = pthread_join(tid1,NULL);
- if(ret != 0){
- printf("pthread_join:%s",strerror(ret));
- return -1;
- }
- ret = pthread_join(tid2,NULL);
- if(ret != 0){
- printf("pthread_join:%s",strerror(ret));
- return -1;
- }
- return 0;
- }
after add gi:1.
before substract gi:1.
after substract gi:0.
before add gi:0.
after add gi:1.
before substract gi:1.
after substract gi:0.
before add gi:0.
after add gi:1.
before substract gi:1.
after substract gi:0.
before add gi:0.
after add gi:1.
before substract gi:1.
after substract gi:0.
before add gi:0.
after add gi:1.
before substract gi:1.
after substract gi:0.
自旋锁
自旋锁与互斥量类似,但它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(自旋)状态。自旋锁可用于以下情况:锁被持有的时间短,而且线程并不希望在重新调度上花费太多的成本。
自旋锁通常作为底层原语用于实现其他类型的锁。根据它们所基于的系统体系结构,可以通过使用测试并设置指令有效地实现。当然这里说的有效也还是会导致CPU资源的浪费:当线程自旋等待锁变为可用时,CPU不能做其他的事情。这也是自旋锁只能够被位置一小段时间的原因。
自旋锁用在非抢占式内核中时是非常有用的:除了提供互斥机制以外,它们会阻塞中断,这样中断处理程序就不会让系统陷入死锁状态,因为它需要获取已被加锁的自旋锁(把中断想成另一种抢占)。在这种类型的内核中,中断处理程序不能休眠,因为它们能用的同步原语只能是自旋锁。
屏障
屏障(barrier)是用户协调多个线程并行工作的同步机制。屏障允许每个线程等待,直到所有的合作线程都到达某一点,然后从该点继续执行。我们已经看到一种屏障,pthread_join函数是一种屏障,允许一个线程等待,直到另一个线程退出。
但是屏障对象的概念更广,它们允许任意数量的线程等待,直到所有的线程处理完工作,而线程不需要退出。所有线程到达屏障后可以直接工作。
互斥锁和自旋锁的区别:
自旋锁是一种非阻塞锁,也就是说,如果某线程需要获取自旋锁,但该锁已经被其他线程占用时,该线程不会被挂起,而是在不断的消耗CPU的时间,不停的试图获取自旋锁。
互斥量是阻塞锁,当某线程无法获取互斥量时,该线程会被直接挂起,该线程不再消耗CPU时间,当其他线程释放互斥量后,操作系统会激活那个被挂起的线程,让其投入运行。
两种锁适用于不同场景:
如果是多核处理器,如果预计线程等待锁的时间很短,短到比线程两次上下文切换时间要少的情况下,使用自旋锁是划算的。
如果是多核处理器,如果预计线程等待锁的时间较长,至少比两次线程上下文切换的时间要长,建议使用互斥量。
如果是单核处理器,一般建议不要使用自旋锁。因为,在同一时间只有一个线程是处在运行状态,那如果运行线程发现无法获取锁,只能等待解锁,但因为自 身不挂起,所以那个获取到锁的线程没有办法进入运行状态,只能等到运行线程把操作系统分给它的时间片用完,才能有机会被调度。这种情况下使用自旋锁的代价 很高。
如果加锁的代码经常被调用,但竞争情况很少发生时,应该优先考虑使用自旋锁,自旋锁的开销比较小,互斥量的开销较大。