Linux线程同步与进程通信
线程同步与进程通信
线程同步
互斥量
-
临界资源:在一段时间内只允许一个任务(线程或进程)访问资源。任务之间采用互斥的方式访问临界资源
-
互斥量:
pthread_mutex_t mutex;
初始化、加锁、解锁、销毁- 加锁:
int pthread_mutex_lock(); int pthread_mutex_trylock();
在访问临界资源前,对互斥量进行加锁。trylock()
未加锁则加锁,加锁后不重复加锁。 - 解锁:
int pthread_mutex_unlock();
访问完成后对互斥量解锁 - 销毁:
int pthread_mutex_destory();
互斥量使用完毕后对互斥量进行销毁,释放资源。
- 加锁:
条件变量
-
任务同步:多个线程都要访问临界资源又要相互合作,一个任务的执行依赖与另一个任务的执行情况。
-
条件变量:
pthread_cond_t cond;
和互斥量一起使用,允许线程以互斥的方式阻塞等待条件的发生即为同步关系- 触发条件变量的线程:互斥量加锁>>某一操作>>触发条件变量>>互斥量解锁
- 等待条件变量的线程:互斥量加锁>>等待条件变量>>某一操作>>互斥量解锁
- 销毁:
pthread_cond_destory();
条件变量不再使用后进行销毁,释放空间 - 等待条件变量:
pthread_cond_wait();
使得调用进程进入阻塞状态,直到条件触发 - 触发条件变量:
pthread_cond_signal();/pthread_cond_broadcast();
可触发并唤醒等待条件变量的线程
-
条件变量与互斥量要配合使用
-
条件变量的使用场景伴随着临界资源的使用
-
在调用
pthread_cond_wait();
前需要使互斥量处于加锁状态,通过原子操作将调用线程放到该条件变量等待线程队列(临界资源)中//等待条件变量的操作 pthread_mutex_lock(); pthread_cond_wait(); pthread_mutex_unlock();
-
-
条件变量的使用
读写锁
-
读写关系:读写互斥、写写互斥、读读不互斥
-
读写锁:
pthread_rwlock_t;
- 加读锁:
阻塞加锁pthread_rwlock_rdlock();/非阻塞加锁pthread_rwlock_tryrdlock();/限时加读锁pthread_rwlock_timedrdlock();
- 加写锁:
阻塞加锁pthread_rwlock_wrlock();/非阻塞加锁pthread_rwlock_trywrlock();/限时加读锁pthread_rwlock_timedwrlock();
- 解锁:统一解锁函数,最近配对原则解锁
pthread_rwlock_unlock();
- 加读锁:
进程通信
-
管道和命名管道:文件的形式实现不同进程共享资源
-
XSI IPC机制:LINUX系统使用的进程通信机制
功能 信号量 共享内存 消息队列 创建或打开一个IPC对象,获得对IPC机制的访问权 semget shmget msgget IPC操作:信号量操作;连接/释放共享内存;发送/接收消息 semop shmat/shmdt msgsnd/msgrcv IPC控制:获得/修改IPC对象状态,“删除”IPC对象 semctl shmctl msgctl
消息队列
-
消息队列:消息的链表,有写或者读权限的进程可以按照一定的规则添加或者读取消息
-
消息队列的操作
sys/types.h sys/ipc.h sys/msg.h
- 打开或创建消息队列对象:
int msgget();
- 从消息队列接收消息:
int msgrcv();
- 向消息队列发送消息:
int msgsnd();
- 消息队列控制操作:
int msgctl();
- 打开或创建消息队列对象:
信号量
-
互斥信号量:任务之间互斥访问临界资源 初始值为1
-
计数信号量:任务之间竞争访问共享资源 初始值大于1,表示共享资源个数
-
二值信号量:任务之间的同步机制 初始值为0
-
信号量的数据结构
struct s { int count; //资源计数 Queue queue; //任务阻塞队列 }; int init(); // 初始化 int P(); // P操作 int V(); // V操作
-
P操作:分配资源
--s.count; if(s.count < 0) { 调用进程进入s.queue; 阻塞调用进程; }
-
V操作:释放资源
++s.count; if(s.count <= 0 ) { 从阻塞队列s.queue中取出一个进程P; 进程P进入就绪队列; }
-
信号量集的操作
sys/types.h sys/ipc.h sys/sem.h
-
创建或者打开信号量集对象
int semget();
#include<stdio.h> #include<sys/sem.h> #define MYKEY 0x1a0a //定一个ipc的key值 int main() { int semid; semid = semget(MYKEY,1,IPC_CREAT|IPC_R|IPC_W|IPC_M); //创建一个信号量集对象 printf("semid = %d\n",semid); return 0; }
-
信号量PV操作
int semop();
:根据参数short sem_op;
判断执行的操作类型sem_op > 0
:信号量V操作,增加信号量的值sem_op < 0
:信号量P操作,减少信号量的值sem_op = 0
:对信号量的当前值是否为0的测试
//实现P操作 static int semaphore_v(void) { struct sembuf sem_b; sem_b.sem_num = 0; //信号量编号 sem_b.sem_op = -1; // P操作 sem_b.sem_fg = SEM_UNDO; //在进程没释放信号量而退出时,系统自动释放该进程中未释放的信号量 if(semop(sem_id, &sem_b,1) == -1) { fprintf(stderr,"semaphore_p failed\n"); return 0; } return 1; } //实现V操作 static int semaphore_v(void) { struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1; // V操作 sem_b.sem_fg = SEM_UNDO; if(semop(sem_id, &sem_b,1) == -1) { fprintf(stderr,"semaphore_v failed\n"); return 0; } return 1; }
-
信号量控制
int semctl();
:int cmd;
控制命令参数- 对信号量集的控制命令:
IPC_RMID
删除;IPC_SET
设置参数;IPC_STAT
获取参数;IPC_INFO
获取系统信息 - 对信号量的控制命令:
SETVAL
设置信号量的值;GETVAL
获取信号量的值;GETPID
获取信号量拥有者的PID值
//信号量初始化 int init_sem(int sem_id, int init_value) { union semun_sem_union; sem_union.val = init_value; if(semctl(sem_id,0,SETVAL,sem_union) == -1) { perror("Initialize semaphore"); return -1; } return 0; } //从系统中删除信号量 int del_sem(int sem_id) { union semun sem_union; if(semctl(sem_id,0,IPC_RMID,sem_union) == -1) { perror("Initialize semaphore"); return -1; } }
- 对信号量集的控制命令:
-
共享内存
-
共享内存:不同进程可以将同一段内存空间链接到自己的地址空间中,类似物理空间中的全局变量
-
共享内存的操作
sys/types.h sys/ipc.h sys/shm.h
- 创建或者打开共享内存对象
int shmget();
- 将共享内存链接到调用的进程的地址空间
void *shmat();
- 删除进程的共享内存链接
int shmdt();
- 对共享内存的操作
int shmctl();
- 创建或者打开共享内存对象
-
共享内存应用–生产者/消费者问题
//缓存池结构 struct BufferPool { char Buffer[5][100]; int index[5]; };
更多推荐
所有评论(0)