1.进程间通信
1. 信号 -- 通知
2. 管道 -- 无名管道 有名管道
3. IPC通信 -- 进程间通信
共享内存,消息队列,信号量集
4. 套接字 -- 网络通信 网络聊天室
2.信号的概念
信号 -- 类似于通知,是一种软中断机制;
查看信号:kill -l
前31个是不可靠信号;
后31个是可靠信号,支持排队;
2号信号 -- 杀死进程
3号信号 -- 杀死进程
9号信号 -- 专门用来杀死进程--不允许忽略或者改造
14号信号 -- 闹钟信号 -- 杀死进程
17号信号 -- 子进程只要状态发生变化,父进程就能够接收到17号信号;
18号信号 -- 恢复由19号信号暂停的进程
19 号信号 -- 暂停进程
信号的产生:
方式1:kill -sig pid
kill -2 pid
方式2:快捷方式:ctrl+c
方式3:内核发送信号 (段错误)
信号的相关API
1》信号的发送函数
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
形参:pid -- 进程号
sig -- 信号
返回值:成功返回0,失败返回-1;
2》给自己发送信号
#include <signal.h>
int raise(int sig);
形参:信号
3》闹钟函数:alarm
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:设置闹钟,在seconds产生闹钟信号
形参:seconds -- 秒
返回值:在调用alarm之前,已经设置过闹钟返回上一次闹钟的剩余时间;
4》pause -- 阻塞性函数,直到有信号产生会解除阻塞;
#include <unistd.h>
int pause(void);
注意:alarm不建议和sleep一块用;
自己实现一个sleep功能;
5》信号处理函数
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
形参:signum -- 信号
handler -- 对信号的处理方式
SIG_IGN : 对该信号忽略
SIG_DFL : 对该信号默认
函数名 : 捕获到signum信号之后,执行该函数名对应的函数
插入:
atexit -- 注册退出清理函数
#include <stdlib.h>
int atexit(void (*function)(void));
形参:函数指针; 传递的时候只能写函数名;
功能:在程序正常退出前执行形参中对应的函数
两个例题
1.结合信号中的函数,自己实现sleep的功能
#include<stdio.h>
#include <signal.h>
#include<unistd.h>
void fun(int sig);
int main()
{
signal(14,fun);//对alarm闹钟进行改造,使其默认秒数结束杀死进程功能替换
//为fun函数啥也不做,即实现了隔一秒一打印
int i=0;
while (1)
{
printf("%d\n",i);
alarm(1);
pause();//堵塞程序在此一秒
i++;
}s
return 0;
}
void fun(int sig)
{
}
- 完成无界面的MP3播放器多进程+信号
#include<stdio.h>
#include<glob.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include<stdlib.h>
void Fun(int sig);
void print(void);
void Clean(void);
int cur=0;
pid_t pid=0;
glob_t song;
int main()
{
atexit(Clean);//首先防止光标消失,输入终端不显示
glob("/home/fuc/音乐/*.mp3",0,NULL,&song);//通过glob把该文件里的歌曲存放到song里
pid=fork();//创建子进程
if(pid==0)//子进程播放歌曲
{
execlp("mpg123","mpg123",song.gl_pathv[cur],NULL);
}
else if(pid>0)
{
int num=0;
signal(17,Fun);//定义17信号
print();
while(1)
{
scanf("%d",&num);
getchar();
switch(num)
{
case 1:kill(pid,19);printf("音乐已暂停\n");break;
case 2:kill(pid,18);printf("音乐已播放\n");break;
case 3:
cur++;
if(cur==song.gl_pathc)
cur=0;
kill(pid,9);
printf("下一首\n");
break;
case 4:
cur--;
if(cur==-1)//第0首歌的上一首歌为本歌单最后一首
cur=song.gl_pathc-1;//本歌单最后一首
kill(pid,9);
printf("上一首\n");
break;
case 0:signal(17,SIG_IGN);kill(pid,9);printf("音乐已退出\n");return 0;
//先恢复signal忽略17信号的作用,再退出防止父进程退出,子进程还在继续运行
}
}
}
return 0;
}
void print(void)
{
printf("--1 暂停 -- --2 恢复 -- --3 下一首 -- --4 上一首 --\n");
}
void Clean(void)
{
system("stty echo");//回显
printf("\033[?025h");//光标
}
void Fun(int sig)
{
int sta=0;
pid_t res=waitpid(pid,&sta,WNOHANG);//此时waitpid为非阻塞,把子进程的结束状态赋值给sta
if(res==pid)//排除暂停和恢复带来的干扰
{
if(WIFEXITED(sta))//当sta值为非0则说明子进程是自然结束的
{
cur++;//下一首
if(cur==song.gl_pathc)
{
cur=0;
}
}
pid=fork();//继续创建子进程进行播放
if(pid==0)
{
execlp("mpg123","mpg123",song.gl_pathv[cur],NULL);
}
}
}