线程间同步机制
- 概述
- 保护机制
- 互斥锁
- 创建互斥锁 pthread_mutex_init
- 加锁 pthread_mutex_lock
- 解锁 pthread_mutex_unlock
- 删除锁 pthread_mutex_destroy
- 条件变量
- 创建条件变量 pthread_cond_init
- 激活条件变量 pthread_cond_signal
- 等待条件变量 pthread_cond_wait
- 删除条件变量 pthread_cond_destroy
- 信号灯
- 创建信号量 sem_init
- 信号量加保护 sem_wait
- 信号量解保护 sem_post
- 信号量删除 sem_destroy
- 线程间通信的例子
概述
同进程内的所有线程共同使用进程的内存空间,并且线程可以在直接应用层完成,因此线程和线程之间的通信使用“全局变量”即可完成通信。但是由于 Linux 系统没有数据保护方式,所在在线程通信的时候需要进行数据的“同步保护”。
在同进程中的多个线程都要操作的数据进行保护时,只允许一个线程操作要保护的内容。Linux 系统使用“信号量”、“互斥锁”以及“条件变量”来实现数据同步保护。实现数据保护的流程为:
①创建一种使用的保护机制(信号量、互斥锁或条件变量)。
②在操作保护内容之前,加保护(一旦本线程加保护成功,其他线程在操作就会阻塞)。
③在操作保护内容后,解保护(其他线程自动取消阻塞)。
④删除保护机制。
注:线程间的数据保护机制是一种人为的约束,一定要所有线程都要遵循这个操作才会有意义,同时“加保护”、“解保护”操作在一个线程中一定要成对出现。
保护机制
互斥锁
创建互斥锁 pthread_mutex_init
头文件
#include <pthread.h>
函数原型:int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
参数介绍:
mutex:互斥锁编号。
attr:互斥锁的属性。
返回值:成功返回 0,失败返回-1,并且设置 errno 变量来指示错误的发生。
pthread_mutex_t mutexid;
pthread_mutex_init(&mutexid,NULL);
加锁 pthread_mutex_lock
头文件
#include <pthread.h>
函数原型:int pthread_mutex_lock(pthread_mutex_t *mutex);
参数介绍:
mutex:互斥锁编号。
返回值:成功返回 0,失败返回-1,并且设置 errno 变量来指示错误的发生。
pthread_mutex_lock(&mutexid);
解锁 pthread_mutex_unlock
头文件
#include <pthread.h>
函数原型:int pthread_mutex_unlock(pthread_mutex_t *mutex);
参数介绍:
mutex:互斥锁编号。
返回值:成功返回 0,失败返回-1,并且设置 errno 变量来指示错误的发生。
返回值:
pthread_mutex_unlock(&mutexid);
删除锁 pthread_mutex_destroy
头文件
#include <pthread.h>
函数原型:int pthread_mutex_destroy(pthread_mutex_t *mutex)
参数介绍:
mutex:互斥锁编号。
返回值:成功返回 0,失败返回-1,并且设置 errno 变量来指示错误的发生。
返回值:
pthread_mutex_destroy(&mutexid);
条件变量
创建条件变量 pthread_cond_init
头文件
#include <pthread.h>
函数原型:int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
参数介绍:
cond:条件变量编号。
mutex:条件变量的属性。
返回值:成功返回 0,失败返回-1,并且设置 errno 变量来指示错误的发生。
pthread_cond_t condid;
pthread_cond_init(&condid,NULL);
激活条件变量 pthread_cond_signal
头文件
#include <pthread.h>
函数原型:int pthread_cond_signal(pthread_cond_t *cond);
参数介绍:
cond:条件变量编号。
返回值:成功返回 0,失败返回-1,并且设置 errno 变量来指示错误的发生。
pthread_cond_signal(&condid);
等待条件变量 pthread_cond_wait
头文件
#include <pthread.h>
函数原型:int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
参数介绍:
cond:条件变量编号。
mutex:条件变量的属性。
返回值:成功返回 0,失败返回-1,并且设置 errno 变量来指示错误的发生。
pthread_cond_wait(&condid,&mutexid);
删除条件变量 pthread_cond_destroy
头文件
#include <pthread.h>
函数原型:int pthread_cond_destroy(pthread_cond_t *cond);
参数介绍:
cond:条件变量编号。
返回值:成功返回 0,失败返回-1,并且设置 errno 变量来指示错误的发生。
pthread_cond_destroy(&condid);
信号灯
创建信号量 sem_init
头文件
#include <semaphore.h>
函数原型:==int sem_init(sem_t *sem, int pshared, unsigned int value); ==
参数介绍:
sem:信号量编号。
pshared:信号量在作用范围(0:本进程中多个线程共享可用;非 0:在当前登录用户的多个进程之间共享)。
value:信号量的信号值。
返回值:成功返回 0,失败返回-1,并且设置 errno 变量来指示错误的发生。
sem_t semid;
sem_init(&semid,0, 1);
信号量加保护 sem_wait
头文件
#include <semaphore.h>
函数原型:int sem_wait(sem_t * sem);
参数介绍:
sem:信号量编号。
返回值:成功返回 0,失败返回-1,并且设置 errno 变量来指示错误的发生。
sem_wait(&semid);
信号量解保护 sem_post
头文件
#include <semaphore.h>
函数原型:int sem_post(sem_t * sem);
参数介绍:
sem:信号量编号。
返回值:成功返回 0,失败返回-1,并且设置 errno 变量来指示错误的发生。
sem_post(&semid);
信号量删除 sem_destroy
头文件
#include <semaphore.h>
函数原型:int sem_destroy(sem_t * sem);
参数介绍:
sem:信号量编号。
返回值:成功返回 0,失败返回-1,并且设置 errno 变量来指示错误的发生。
sem_destroy(&semid);
线程间通信的例子
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <pthread.h>
#include <semaphore.h>
char path[10];
//信号服务函数
void * son_fun(void * arg)
{
int fd2 = open(path,O_RDWR); //打开读管道
while(1)
{
char rb[512] = {0};
read(fd2,rb,sizeof(rb));
printf("%s说:%s\n",(char *)arg,rb);
}
close(fd2); //关闭读管道
}
//关于argv:
// 1 是读通道 2 是写通道 3 是自己的信号 4 是发的信号
int main(int argc,char *argv[])
{
//init
pthread_t id;
strcpy(path,argv[2]);
//创建管道
int val1 = mkfifo(argv[1],0666);
int val2 = mkfifo(argv[2],0666);
//打开管道
int fd1 = open(argv[1],O_RDWR); //写管道
//创建子线程
pthread_create(&id,NULL,son_fun,"he say");//创建子线程
//等待写入
while(1)
{
char wb[512] = {0};
gets(wb);
write(fd1,wb,strlen(wb));
}
close(fd1);
pthread_join(id,NULL);
return 0;
}