目录
前言
线程同步的实现方法:信号量、互斥锁、条件变量、读写锁。(考点)
下面就对着四种方法进行展开描述
与进程间通信的信号量类似,参考链接:【Linux】进程间通信——信号量
头文件
#include
sem_init()
int sem_init(sem_t *sem,int pshared,unsigned int value);
sem_post()
int sem_post(sem_t *sem);
sem_wait()
int sem_wait(sem_t *sem);
sem_destroy()
int sem_destroy(sem_t *sem);
用代码实现打印机对ABC顺序打印的操作,如下图所示,使用信号量完成代码:

- #include
- #include
- #include
- #include
- #include
- #include
-
- sem_t sema;
- sem_t semb;
- sem_t semc;
-
- void* funa(void* arg)
- {
- for(int i=0;i<5;i++)
- {
- sem_wait(&sema);//ps1
- printf("A");
- fflush(stdout);
- sem_post(&semb);//vs2
- }
- }
- void* funb(void* arg)
- {
- for(int i=0;i<5;i++)
- {
- sem_wait(&semb);
- printf("B");
- fflush(stdout);
- sem_post(&semc);
- }
- }
- void* func(void* arg)
- {
- for(int i=0;i<5;i++)
- {
- sem_wait(&semc);
- printf("C");
- fflush(stdout);
- sem_post(&sema);
- }
- }
-
- int main()
- {
- //初始化信号量
- sem_init(&sema,0,1);
- sem_init(&semb,0,0);
- sem_init(&semc,0,0);
-
- //创建线程
- pthread_t id1,id2,id3;
- pthread_create(&id1,NULL,funa,NULL);
- pthread_create(&id2,NULL,funb,NULL);
- pthread_create(&id3,NULL,func,NULL);
-
- pthread_join(id1,NULL);
- pthread_join(id2,NULL);
- pthread_join(id3,NULL);
-
- sem_destroy(&sema);
- sem_destroy(&semb);
- sem_destroy(&semc);
- exit(0);
- }

由上面的程序可知,信号量的使用是A在读取时,阻止B,C的读取,这样拉低程序性能,读取的时候其实可以三个一起读,而在写操作的时候不能读,因此引入读写锁进行优化
- pthread_rwlock_init();//初始化
-
- pthread_rwlock_destroy();//销毁
-
- pthread_rwlock_rdlock();//读
-
- pthread_rwlock_wrlock();//读写
-
- pthread_rwlock_unlock();//解锁
要求:
代码实现读锁阻止写锁,写锁阻止读锁和写锁。其中fun1和fun2是对文件的读取,fun3是对文件写操作。
- #include
- #include
- #include
- #include
- #include
- #include
-
- pthread_rwlock_t lock;
-
- void* fun1(void* arg)
- {
- for(int i=0;i<5;i++)
- {
- pthread_rwlock_rdlock(&lock);
- printf("fun1 read start----\n");
- sleep(1);
- printf("fun1 over\n");
- pthread_rwlock_unlock(&lock);
- sleep(1);
- }
- }
- void* fun2(void* arg)
- {
- for(int i=0;i<5;i++)
- {
- pthread_rwlock_rdlock(&lock);
- printf("fun2 read start----\n");
- sleep(2);
- printf("fun2 over\n");
- pthread_rwlock_unlock(&lock);
- }
- }
- void* fun3(void* arg)//写
- {
- for(int i=0;i<5;i++)
- {
- pthread_rwlock_wrlock(&lock);
- printf("fun3 read start----\n");
- sleep(3);
- printf("fun3 over\n");
- pthread_rwlock_unlock(&lock);
- }
- }
- int main()
- {
- pthread_rwlock_init(&lock,NULL);
- pthread_t id1,id2,id3;
- pthread_create(&id1,NULL,fun1,NULL);
- pthread_create(&id2,NULL,fun2,NULL);
- pthread_create(&id3,NULL,fun3,NULL);
- pthread_join(id1,NULL);
- pthread_join(id2,NULL);
- pthread_join(id3,NULL);
- pthread_rwlock_destroy(&lock);
- exit(0);
- }

用的时候加锁,如果已经被别的进程加锁,那么该进程就只能被阻塞着。
互斥锁可以理解为信号量的子集
头文件
#include
返回值:成功返回0,失败返回错误码
参数:与信号量类似,都是一个提前声明过的对象指针。对互斥锁来说,这个对象的类型为pthread_mutex_t。
pthread_mutex_init——初始化
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *mutexattr);
用于设置互斥量的属性,控制互斥量的行为
pthread_mutex_lock——加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
pthread_mutex_unlock——解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_mutex_destroy——销毁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
用代码实现互斥锁的使用,在打印机内A使用前加锁,使用后解锁,B在A使用的时候阻塞,如下图·所示:

代码:
- #include
- #include
- #include
- #include
- #include
-
- pthread_mutex_t mutex;
-
- void* fun1(void* arg)
- {
- for(int i=0;i<5;i++)
- {
- pthread_mutex_lock(&mutex);
- printf("A");
- fflush(stdout);
- int n=rand()%3;
- sleep(n);
- printf("A");
- fflush(stdout);
- pthread_mutex_unlock(&mutex);
- n=rand()%3;
- sleep(n);
- }
- }
-
- void* fun2(void* arg)
- {
- for(int i=0;i<5;i++)
- {
- pthread_mutex_lock(&mutex);
- printf("B");
- fflush(stdout);
- int n=rand()%3;
- sleep(n);
- printf("B");
- fflush(stdout);
- pthread_mutex_unlock(&mutex);
- n=rand()%3;
- sleep(n);
- }
- }
-
- int main()
- {
- pthread_mutex_init(&mutex,NULL);//初始化
- pthread_t id1,id2;
- pthread_create(&id1,NULL,fun1,NULL);
- pthread_create(&id2,NULL,fun2,NULL);
- pthread_join(id1,NULL);
- pthread_join(id2,NULL);
- pthread_mutex_destroy(&mutex);//销毁
- exit(0);
- }
运行结果:

条件变量提供了一种线程间的通知机制:当某个共享数据达到某个值的时候,唤醒等待 这个共享数据的线程。
唤醒时,如果线程不在等待队列中的(条件变量为空),此时唤醒就无意义
头文件
#include
- int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr);
- int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
- int pthread_cond_signal(pthread_cond_t *cond); //唤醒单个线程
- int pthread_cond_broadcast(pthread_cond_t *cond); //唤醒所有等待的线程
- int pthread_cond_destroy(pthread_cond_t *cond);
下面代码举例说明funa使用时加锁,用完解锁。funb使用时加锁,用完解锁。键盘输入数据唤醒funa,funb其中一个进行读取。如果键盘输入为end,funa,funb同时被唤醒,退出进程。
加锁的目的防止被他人唤醒被他人加入等待队列
- #include
- #include
- #include
- #include
- #include
- #include
-
- pthread_mutex_t mutex;
- pthread_cond_t cond;
-
- void* funa(void* arg)
- {
- char*s=(char*)arg;//退化为指向数组首地址指针
- while(1)//先阻塞,直到被唤醒
- {
- pthread_mutex_lock(&mutex);//加锁 用互斥锁保护
- pthread_cond_wait(&cond,&mutex);//加锁,解锁
- pthread_mutex_unlock(&mutex);//解锁
-
- if(strncmp(s,"end",3)==0)
- {
- break;
- }
- printf("funa: %s",s);
- }
- }
- void* funb(void* arg)
- {
- char*s=(char*)arg;//退化为指向数组首地址指针
- while(1)//先阻塞,直到被唤醒
- {
- pthread_mutex_lock(&mutex);//加锁 用互斥锁保护
- pthread_cond_wait(&cond,&mutex);//加锁,解锁
- pthread_mutex_unlock(&mutex);//解锁
-
- if(strncmp(s,"end",3)==0)
- {
- break;
- }
- printf("funb: %s",s);
- }
- }
-
- int main()
- {
- pthread_mutex_init(&mutex,NULL);
- pthread_cond_init(&cond,NULL);
- char buff[128]={0};
- pthread_t id1,id2;
- pthread_create(&id1,NULL,funa,(void*)buff);
- pthread_create(&id2,NULL,funb,(void*)buff);
- while(1)
- {
- fgets(buff,128,stdin);
- if(strncmp(buff,"end",3)==0)
- {
- //唤醒所有线程
- pthread_cond_broadcast(&cond);
- break;
- }
- else
- {
- //唤醒一个线程
- pthread_cond_signal(&cond);
- }
-
- }
- pthread_join(id1,NULL);
- pthread_join(id2,NULL);
- pthread_mutex_destroy(&mutex);
- pthread_cond_destroy(&cond);
- }
