进程 VS 线程通信
进程:共享内存,消息队列,管道,信号(条件变量,锁,信号量需要搭配共享内存使用);
线程:信号,条件变量,锁,信号量
代码示例
使用父子子进程交替打印进行演示
sem_init + 共享内存
重点介绍 sem_init 函数参数
int sem_init(sem_t *sem, int pshared, unsigned int value);
第一个参数sem——信号量地址
第二个参数pshared——0:进程内部通信;非0:进程间通信,必须要配合共享内存一起使用
第三个参数——指定信号量的初始值
#include <iostream>
#include <vector>
using namespace std;
#include <semaphore.h>// 信号量
#include <pthread.h>
#include <sys/ipc.h> // 共享内存
#include <sys/shm.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
// 进程间通信 —— 两个进程交替打印
// 1. sem_init + 共享内存
class Text1
{
public:
struct SemData
{
int flag = 0;
sem_t father;
};
const string pathname = "/tmp";
void Main()
{
key_t key = ftok(pathname.c_str(),666);
int shmid = shmget(key,sizeof(SemData),IPC_CREAT | 0666);// 创建
if(shmid == -1){
perror("shmget");
exit(1);
}
cout << shmid << endl;
SemData* mem = (SemData*)shmat(shmid,nullptr,0);
if(mem == nullptr){
perror("shmat");
exit(2);
}
sem_init(&mem->father,1,1);// 进程间共享
int pid = 0;
if(pid = fork()){
// 父进程
while(1){
sem_wait(&mem->father);
printf("father: %d\n",mem->flag++);
if(waitpid(pid,nullptr,WNOHANG)){
break;
}
sem_post(&mem->father);
sleep(1);
}
shmdt(mem);
shmctl(shmid,IPC_RMID,nullptr);
}else{
while(1){
sem_wait(&mem->father);
if(mem->flag > 10){
puts("children exit");
sem_post(&mem->father);
exit(0);
}
printf("children: %d\n",mem->flag++);
sem_post(&mem->father);
sleep(1);
}
}
}
};
int main()
{
Text1 test1;
test1.Main();
return 0;
}
sem_open 进程直接通信
sem_open 参数介绍
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
第一个参数:以/
开头的文件路径在测试时发现,就算不加/
并且使用不存在的路径也是可以运行的
第二个参数:打开标志——和linux中的文件标志一样
第三个参数:创建的信号量的使用权限,一般使用0666
第四个参数:信号量的数量
#include <iostream>
#include <vector>
using namespace std;
#include <semaphore.h>// 信号量
#include <pthread.h>
#include <sys/ipc.h> // 共享内存
#include <sys/shm.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
// sem_open 直接进程间通信
class Text2
{
public:
void test()
{
const string path = "/tmp";
sem_t* sem_father = sem_open(path.c_str(),O_CREAT | O_EXCL, 0644,1);
int pid = 0;
if(pid = fork()){
// 父进程
int cnt = 1;
while(1){
sem_wait(sem_father);
printf("father: %d\n",cnt);
cnt += 2;
if(waitpid(pid,nullptr,WNOHANG)){
break;
}
sem_post(sem_father);
sleep(1);
}
}else{
int cnt = 0;
while(1){
sem_wait(sem_father);
if(cnt > 10){
puts("children exit");
sem_post(sem_father);
exit(0);
}
printf("children: %d\n",cnt);
cnt+=2;
sem_post(sem_father);
sleep(1);
}
}
}
void Main()
{
test();
}
};
int main()
{
Text2 test2;
test2.Main();
return 0;
}
信号通信
注意
SIGUSR1,SIGUSR2
是留给用户自定义行为的信号,我们这里选择SIGUSR1
// 使用信号的方式进行进程间通信
class Text3
{
public:
// static volatile int flag;
static volatile int flag;
static void handle(int sig)
{
flag = 1;
}
void test()
{
signal(SIGUSR1,handle);
int pid=0;
if(pid = fork()){
// 父进程
while(1){
while(!flag) {}
flag=0;
printf("father\n");
if(waitpid(pid,nullptr,WNOHANG)){
break;
}
kill(pid,SIGUSR1);
sleep(1);
}
}else{
while(1){
printf("children\n");
kill(getppid(),SIGUSR1);
while(!flag){}
flag=0;
sleep(1);
}
}
}
void Main()
{
test();
}
};
volatile int Text3::flag = 0;
int main()
{
Text3 test3;
test3.Main();
return 0;
}