原文链接:C++ Linux多进程同步-命名信号量
匿名信号量一般是作为全局变量存在,用于线程通信,如果要实现进程通信需要定义命名变量.
进程同步
进程之间也可以使用信号量同步,信号量一般有两种库实现:POSIX信号量和C++20(<semaphore.h>) 以及 SystemV信号量(<sys/sem.h>传统的进程间同步机制)
标准库
<semaphore.h>
<semaphore.h>提供两种信号:POSIX和C++20
POSIX信号量更底层,支持进程和线程同步.而counting_semaphore本身只能支持线程同步,而且仅C++20适用
POSIX信号量
POSIX信号量是C标准库中的,兼容性更高
1 2 3 4 5 6 7 8
| sem_t 本身就是一个信号量类型 sem_init(sem_t *sem, int pshared, unsigned int value): 初始化一个信号量。 pshared指明共享范围,不直接表示进程信号量,而 sem_wait(sem_t *sem): 等待信号量。 sem_post(sem_t *sem): 释放信号量。 sem_destroy(sem_t *sem): 销毁信号量。 sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value); 创建命名信号量,命名信号量能够实现进程同步 value初始值 mode权限 oflag为标志,O_CREAT(打开,不存在则创建)和O_EXCL(存在则报错) return SEM_FAILED失败 或 信号量指针 int sem_unlink(const char *name); 删除命名信号量
|
counting_semaphore信号量
c++20提供的counting_semaphore, binary_semaphore新的封装(binary_semaphore不如使用mutex实现或者使用counting_semaphore实现二值)
1 2 3 4 5 6 7
| counting_semaphore(ptrdiff_t desired) :构造函数,传入初始信号值. ptrdiff_t是两个指针差值范围,4或8字节(机器字长) 范围大于等于int,一般可以用int代替 void acquire() 占用 void release() 阻塞 bool try_acquire() 不阻塞占用,true 占用成功,false 占用失败 bool try_acquire_for(const std::chrono::duration<Rep, Period>& rel_time ) true 表示占用,false 为超出阻塞时间 这个感觉用处不大,过度封装了,实在需要可以自己实现 ptrdiff_t max 计数上限
|
使用命名POSIX信号量实现父进程等待子进程输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include <iostream> #include <semaphore.h> #include <unistd.h> #include <fcntl.h> using namespace std;
void child_process(sem_t* nsem){ cout<<"child print"<<endl; sem_post(nsem); }
int main() { sem_t* nsem=sem_open("name_sem",O_CREAT,0666,0); if (nsem == SEM_FAILED) { perror("sem_open"); exit(EXIT_FAILURE); } pid_t cpid=fork(); if(cpid==-1){ perror("fork"); exit(EXIT_FAILURE); }else if(cpid>0){ sem_wait(nsem); cout<<"parent print"<<"\n"; }else{ sleep(0.005); child_process(nsem); } sem_destroy(nsem); sem_unlink("name_sem"); return 0; }
|
因此使用命名信号量就能实现所有进程之间的同步.只需要每个进程都打开该命名信号量即可
<sys/sem.h>
这个信号量库提供semget,semop,semctl等操作,比较繁琐,了解即可