IPC(Inter-Process Communication)进程间通信,提供了各种进程间通信的方法。在Linux C编程中有几种方法
(1) 半双工Unix管道
(2) FIFOs(命名管道)
(3) 消息队列
(4) 信号量
(5) 共享内存
(6) 网络Socket
1. 信号 (该文章信号是Ubuntu Linux 虚拟机环境下)
在 Ubuntu 中
kill -n 发送第 N 个信号 比如第九个 是 杀死
1~ 31 不可靠信号 34~64 可靠信号
其中 SIGUSR1 与 SIGUSR2 可以用户自定义;
void (* functon)(int) 函数指针 名称在后面的就是该数据的属性
1.1signal库函数
如果想让程序能够处理信号,可以使用 signal库函数,要引入头文件<signal.h>
void (*signal(int sig, void (*func)(int))) (int);
void (*func)(int) 是函数指针
其中int 形参 可以用来判断信号ID;
配合kill 使用 , signal绑定信号与函数指针, 使用kill 发送给进程;
kill( 进程ID , 信号 ); //发送信号给目标进程
特点:
1. 优先级最高,可以打破死循环先执行信号中函数指针的内容,再回去继续进行死循环。
2. 接收的信号没有绑定函数, 会导致进程直接结束代码, 但是进程不会结束,子进程的话会进入僵尸状态。
3. 不可靠信号,如果连续发送太快进程在执行会不管新接收的信号, 一次只处理一条信号。可靠信号就没这个问题。
4. 进程接受到的信号无法识别执行什么,就会意外结束程序, 如果在子进程当中可能会引起僵尸状态。
2.1 无参信号:头文件如果不知道 在Ubuntu 终端中使用 man 函数名 来查询)
signal 与 kill 配合
//信号方案1 不带参
signal(SIGUSR1, signal_funtion);
pid_t id = 0;
id = fork();
int state = 0;
if ( id > 0 )
{
sleep(5);
for (int i = 0; i < 3 ; i++)
{
sleep(2);
//给子进程 id 发送信号
kill(id, SIGUSR1);
}
//接收子进程状态
wait(&state);
while (true)
{
}
}
else
{
while (1)
{
sleep(1);
cout << "子进程: " << getpid() << endl;
}
exit(1);
}
2.2 带参信号:(Ubuntu 目前只能发送int数据)
sigaction 与 sigqueue (该组合也可进行无参信号发送,就是没有signal 方便)
union sigval 该结构体就是传递的带参, 其中只有int能用, 另一个保留的void *参数 暂时官方没完善用不了。
//信号方案2 带参信号
pid_t id = 0;
int state = 0;
struct sigaction act;
act.sa_sigaction = sigaction_function;
act.sa_flags = SA_SIGINFO; //表示设置为带参信号
/*
//这是不带参的写法
struct sigaction act2;
act2.sa_handler = test2;
act2.sa_flags = 0;
*/
sigaction(SIGUSR1, &act, NULL); //绑定信号
//子进程在信号之后生成
id = fork();
if ( id > 0 )
{
sleep(5);
for (int i = 0; i < 3 ; i++)
{
sleep(2);
union sigval value;
value.sival_int = 123;
//给子进程 id 发送信号
sigqueue(id, SIGUSR1, value);
}
//接收子进程状态
wait(&state);
while (true)
{
}
}
else
{
while (1)
{
sleep(1);
cout << "子进程: " << getpid() << endl;
}
exit(1);
}
2.3 信号冲突: ※
两个及以上的命令互相影响,造成程序异常。
信号冲突有两种情况:
不过只解决异种信号冲突的情况, 同种信号(同一个重复发送)会自动排队运行。
//这两个函数绑定 10 与 12 信号 用来测试信号冲突
void test1( int num )
{
cout << " test1 run : " << getpid() << endl;
sleep(20);
cout << " test1 over " << endl;
}
void test2(int num)
{
cout << " test2 over " << endl;
}
//信号冲突 (两个信号及以上, 执行一个信号的时候另外的信号也传递过来互相影响)
/*
两种情况
情况1 :
※情况1:一个信号正在执行处理函数,还在执行没做完,接收到异种信号,
执行函数被打断立刻执行异种信号处理,异种处理完再回去处理未处理完的第一个信号的逻辑
情况2:一个信号正在执行处理函数,还在执行没做完,接到铜钟信号,
执行函数继续执行,完成之后再次下一次函数
口诀: 异种打断, 同种排队
*/
struct sigaction act1;
act1.sa_handler = test1;
act1.sa_flags = 0;
struct sigaction act2;
act2.sa_handler = test2;
act2.sa_flags = 0;
//清空信号集
sigemptyset( &(act1.sa_mask) );
//添加信号集 把SIGUSR2 加到
//sa_mask
/*sigset_t sa_mask 是一个信号集,在调用该信号捕捉函数之前,
将需要block的信号加入这个sa_mask,仅当信号捕捉函数正在执行时
,才阻塞sa_mask中的信号,当从信号捕捉函数返回时进程的信号屏蔽字复位为原先值。*/
sigaddset(&(act1.sa_mask) , SIGUSR2);
sigaction(SIGUSR1 , &act1, NULL);
sigaction(SIGUSR2, &act2, NULL);
while (1)
{
cout << " 进程正在运行: pid = " << getpid() << endl;
sleep(1);
}
2.4 信号未绑定函数指针 (未决信号)
//信号没绑定方法解决方法 使用信号集过滤掉
sigset_t s; // 定义一个信号集
sigemptyset(&s); //清空信号集
sigaddset(&s, SIGUSR1); //添加信号集
sigaddset(&s, SIGUSR2); //添加信号集
//启用信号集过滤
if ( sigprocmask(SIG_BLOCK, &s, NULL) < 0 )
{
perror(" sigprocmask error! ");
}
while (1)
{
cout << " 进程正在运行 ... pid = " << getpid() << endl;
sleep(1);
}