互斥量从本质上说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁。对互斥量进行加锁以后,任何其他试图再次对互斥量加锁的线程将会被阻塞直到当前线程释放该互斥锁。如果释放互斥锁时有多个线程阻塞,所以在该互斥锁上的阻塞线程都会变成可进行状态,第一个变成运行状态的线程可以对互斥量加锁,其他线程在次被阻塞,等待下次运行状态。
pthread_mutex_t 就是POSIX对于mutex的实现。
函数名 | 参数 | 说明 |
pthread_mutex_init | pthread_mutex_t * mutex, constpthread_mutex_t *attr |
初始化一个互斥量,静态方式可以直接使用PTHREAD_MUTEX_INITIALIZER进行赋值初始化 |
pthread_mutex_destroy | pthread_mutex_t *mutex | 释放对互斥变量分配的资源。注意pthread_mutex_init有可能malloc了资源 |
pthread_mutex_lock | pthread_mutex_t *mutex | 如果互斥量已经上锁,调用线程阻塞直至互斥量解锁 |
pthread_mutex_trylock | pthread_mutex_t *mutex | 加锁,如果失败不阻塞 |
pthread_mutex_unlock | pthread_mutex_t *mutex | 解锁 |
当然该初始化
另外一种用法:
与互斥锁不同,条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。
条件变量使我们可以睡眠等待某种条件出现。条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。
条件的检测是在互斥锁的保护下进行的。如果一个条件为假,一个线程自动阻塞,并释放等待状态改变的互斥锁。如果另一个线程改变了条件,它发信号给关联的条件变量,唤醒一个或多个等待它的线程,重新获得互斥锁,重新评价条件。如果两进程共享可读写的内存,条件变量可以被用来实现这两进程间的线程同步。
条件变量的初始化和mutex的初始化差不多,也是有两种方式:
pthread_cond_tmy_condition=PTHREAD_COND_INITIALIZER;
也可以利用函数pthread_cond_init动态初始化。
下面中各个函数的简介。
函数名 | 参数 | 说明 |
pthread_cond_init | pthread_cond_t *cond, const pthread_condattr_t *attr |
初始化 |
pthread_cond_destroy | pthread_cond_t *cond | 回收 |
pthread_cond_wait | pthread_cond_t *cond, pthread_mutex_t *mutex |
等待,无超时 |
pthread_cond_timedwait | pthread_cond_t *cond,pthread_mutex_t *mutex, const struct timespec *abstime |
等待,有超时 |
pthread_cond_signal | pthread_cond_t *cond | 一个在相同条件变量上阻塞的线程将被解锁。如果同时有多个线程阻塞,则由调度策略确定接收通知的线程 |
pthread_cond_broadcast | pthread_cond_t *cond | 将通知阻塞在这个条件变量上的所有线程。一旦被唤醒,线程仍然会要求互斥锁。 |
一个简单使用条件变量进行线程同步的小例子:
/* * pthread_mutex_cond.c * */ #include <pthread.h> #include <stdio.h> #include <stdlib.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int i = 0; void *thread1(void *); void *thread2(void *); int main(void) { pthread_t tid1, tid2; if(pthread_create(&tid1, NULL, thread1, NULL)) exit(1); if(pthread_create(&tid2, NULL, thread2, NULL)) exit(1); if(pthread_join(tid1, NULL)) exit(1); printf("thread1 exit\n"); if(pthread_join(tid2, NULL)) exit(1); printf("thread2 exit\n"); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); exit(0); } void *thread1(void *arg) { printf("thread1 start\n"); while(i <= 6) { pthread_mutex_lock(&mutex); printf("thread1: lock %d\n", __LINE__); printf("thread1 i = %d\n", i); if(i%3 == 0) { printf("thread1:signal 1 %d\n", __LINE__); pthread_cond_signal(&cond); printf("thread1:signal 2 %d\n", __LINE__); } pthread_mutex_unlock(&mutex); printf("thread1: unlock %d\n", __LINE__); sleep(1); //sleep 1s,让线程2得以执行 i++; } pthread_exit((void *)0); } void *thread2(void *arg) { //sleep(1); printf("thread2 start\n"); while(i <= 6) { pthread_mutex_lock(&mutex); printf("thread2: lock %d\n", __LINE__); printf("thread2 i = %d\n", i); if(i%3 != 0) { printf("thread2: wait 1 %d\n", __LINE__); pthread_cond_wait(&cond, &mutex); printf("thread2: wait 2 %d\n", __LINE__); } pthread_mutex_unlock(&mutex); printf("thread2: unlock %d\n", __LINE__); sleep(1); //sleep 1s,让线程1得以执行 } pthread_exit((void *)0); }运行结果:
thread2 start
thread2: lock 65
thread2 i = 0
thread2: unlock 75
thread1 start
thread1: lock 42
thread1 i = 0
thread1:signal 1 46
thread1:signal 2 48
thread1: unlock 51
thread2: lock 65
thread2 i = 0
thread2: unlock 75
thread1: lock 42
thread1 i = 1
thread1: unlock 51
thread2: lock 65
thread2 i = 1
thread2: wait 1 69
thread1: lock 42
thread1 i = 2
thread1: unlock 51
thread1: lock 42
thread1 i = 3
thread1:signal 1 46
thread1:signal 2 48
thread1: unlock 51
thread2: wait 2 71
thread2: unlock 75
thread2: lock 65
thread2 i = 3
thread2: unlock 75
thread1: lock 42
thread1 i = 4
thread1: unlock 51
thread2: lock 65
thread2 i = 4
thread2: wait 1 69
thread1: lock 42
thread1 i = 5
thread1: unlock 51
thread1: lock 42
thread1 i = 6
thread1:signal 1 46
thread1:signal 2 48
thread1: unlock 51
thread2: wait 2 71
thread2: unlock 75
thread2: lock 65
thread2 i = 6
thread2: unlock 75
thread1 exit
thread2 exit
/* * producer-consumer.c * */ #include <stdio.h> #include <stdlib.h> #include <pthread.h> struct msg{ struct msg *next; int num; }; struct msg *head; //共享资源,全局指针初始化为NULL pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void *consumer(void *); void *producer(void *); int main(void) { pthread_t tid1,tid2; int res; srand(time(NULL)); res = pthread_create(&tid1,NULL,producer,NULL); if(res != 0) { perror("thread producer create failed\n"); exit(1); } res = pthread_create(&tid2,NULL,consumer,NULL); if(res != 0) { perror("thread consumer create failed\n"); exit(1); } pthread_join(tid1,NULL); if(res != 0) { perror("join thread producer failed\n"); exit(1); } printf("thread producer exit\n"); pthread_join(tid2,NULL); if(res != 0) { perror("join thread consumer failed\n"); exit(1); } printf("thread consumer exit\n"); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&has_product); exit(0); } void *producer(void *arg) { struct msg *mp; int i; printf("producer thread start\n"); for(i=0;i<6;i++) { printf("producer i = %d\n", i); mp = (struct msg *)malloc(sizeof(struct msg)); mp->num = rand()%100 + 1; printf("Produce %d\n", mp->num); pthread_mutex_lock(&mutex); mp->next = head; head = mp; //生产者生产一个结构体串在链表的表头上 pthread_mutex_unlock(&mutex); pthread_cond_signal(&has_product); sleep(1); //让另一个线程有机会执行 } pthread_exit(NULL); } void *consumer(void *arg) { struct msg *con; int i; printf("consumer thread start\n"); for(i=0;i<6;i++) { printf("consumer i = %d\n", i); pthread_mutex_lock(&mutex); while(head == NULL) { printf("struct msg is null\n"); pthread_cond_wait(&has_product,&mutex); } con = head; //消费者从表头取走结构体 head = con->next; pthread_mutex_unlock(&mutex); printf("Consume %d\n", con->num); free(con); sleep(1); //让另一个线程有机会执行 } pthread_exit(NULL); }运行结果:
consumer thread start
consumer i = 0
struct msg is null
producer thread start
producer i = 0
Produce 52
Consume 52
consumer i = 1
struct msg is null
producer i = 1
Produce 33
Consume 33
consumer i = 2
struct msg is null
producer i = 2
Produce 77
Consume 77
consumer i = 3
struct msg is null
producer i = 3
Produce 86
Consume 86
consumer i = 4
struct msg is null
producer i = 4
Produce 84
Consume 84
consumer i = 5
struct msg is null
producer i = 5
Produce 46
Consume 46
thread producer exit
thread consumer exit