无名管道
无名管道原理
1.通过pipe()创建无名管道,返回管道的两端的文件描述符
2.管道两端分别为读端和写端,且读端和写端固定
3.通信模式:单工
4.通信的进程之间必须具有亲缘关系
无名管道的使用
#include <unistd.h>
int pipe(int pipefd[2]);
//参数 ---- 保存管道两端文件描述符的数组
//返回值 ----- 成功:0,失败:-1
例子:
```
int main(int argc,char **argv)
{
int fd[2];
pid_t pid;
char buf[100];
//创建无名管道
if(pipe(fd) < 0){
perror("pipe");
exit(1);
}
//创建子进程
if((pid = fork()) < 0){
perror("fork");
exit(1);
}else if(!pid){ //子进程:从键盘获取字符串,写到管道中
close(fd[0]);
while(1){
memset(buf,0,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = '\0';
write(fd[1],buf,strlen(buf));
}
}else{ //父进程: 从管道读出数据,并打印到屏幕上
close(fd[1]);
while(1){
memset(buf,0,sizeof(buf));
if(read(fd[0],buf,sizeof(buf)) < 0){
perror("read");
exit(1);
}
printf("%s\n",buf);
}
}
return 0;
}
```
无名管道读写数据注意事项
读端:
管道没有写端的进程,从管道对数据时,read()会返回0
管道有写端的进程:
管道中没有数据,read()会阻塞,等待写数据
管道中有数据,read()读出数据
写端:
管道没有读端进程,向管道写数据时,write()写端的进程会立即结束进程
管道有读端的进程,向管道写数据时,
如果管道没有满,则write()写数据到管道中,
如果管道写满了,则write()阻塞
有名(命名)管道
有名管道原理
1.通过mkfifo()创建有名管道
2.有名管道在文件系统中可见,在目录中可以看到管道文件
3.两个进程通信时,只需要通过open()打开管道,就可以对管道进行读写操作
4.工作模式:半双工
5.可以用于没有亲缘关系的进程之间通信
有名管道创建
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
//参数1 ----- 管道名称
//参数2 ----- 管道的权限: 权限 = mode & ~umask
//返回值 -----成功:0,失败:-1
例如:
```
int main(int argc,char **argv)
{
if(argc != 2){
fprintf(stderr,"Usage: %s <fifoname>\n",argv[0]);
exit(1);
}
if(mkfifo(argv[1],0666) < 0){
perror("mkfifo");
exit(1);
}
return 0;
}
运行:
blob@ubuntu:~/$ ./mkfifo fifo
blob@ubuntu:~/$ ls -l
total 36
prw-rw-r-- 1 blob blob 0 Aug 19 20:27 fifo
```
使用有名管道实现两个进程的通信
输入端:
int main(int argc,char **argv)
{
int fd;
char buf[100];
if(argc != 2){
fprintf(stderr,"Usage: %s<fifoname>\n",argv[0]);
exit(1);
}
if((access(argv[1],F_OK)<0)){
if(mkfifo(argv[1],0666)<0){
perror("mkfifo");
exit(1);
}
}
if((fd=open(argv[1],O_RDWR))<0){
perror("open");
exit(1);
}
while(1){
memset(buf,0,sizeof(buf));
printf("请输入字符串:");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]='\0';
if(write(fd,buf,strlen(buf))<0){
perror("write");
exit(1);
}
if(!strncmp(buf,"quit",4))
break;
}
close(fd);
return 0;
输出端:
int main(int argc,char **argv)
{
int fd;
char buf[100];
int ret;
if(argc != 2){
fprintf(stderr,"Usage: %s<fifoname>\n",argv[0]);
exit(1);
}
if((access(argv[1],F_OK)<0)){
if(mkfifo(argv[1],0666)<0){
perror("mkfifo");
exit(1);
}
}
if((fd=open(argv[1],O_RDWR))<0){
perror("open");
exit(1);
}
while(1){
memset(buf,0,sizeof(buf));
if(ret=read(fd,buf,sizeof(buf))<0){
perror("read");
exit(1);
}
if(!strncmp(buf,"quit",4))
break;
printf("%s\n",buf);
}
close(fd);
return 0;
}
信号
概念
信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式
信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。
如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它;
如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程
进程对信号的响应方式有三种
1.忽略信号:
对信号不做任何处理,但是有两个信号不能忽略:即SIGKILL及SIGSTOP。
2.捕捉信号:
定义信号处理函数,当信号发生时,执行相应的处理函数。
3.执行缺省操作:
Linux对每种信号都规定了默认操作
linux系统对常见信号的缺省(默认)操作
linux系统中信号的种类:
farsight@ubuntu:~/22071/process/day03_code$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
信号名 含义 默认操作
SIGHUP 该信号在用户终端连接(正常或非正常)结束时发出,通常是在终端的控制进程结束时,通知同一 终止
会话内的各个作业与控制终端不再关联。
SIGINT 该信号在用户键入INTR字符(通常是Ctrl-C)时发出,终端驱动程序发送此信号并送到前台进程中的每一个进程。 终止
SIGQUIT 该信号和SIGINT类似,但由QUIT字符(通常是Ctrl-\)来控制。 终止
SIGILL 该信号在一个进程企图执行一条非法指令时(可执行文件本身出现错误,或者试图执行数据段、堆栈溢出时)发出。 终止
SIGFPE 该信号在发生致命的算术运算错误时发出。这里不仅包括浮点运算错误,还包括溢出及除数为0等其它所有的算术的错误。 终止
SIGKILL 该信号用来立即结束程序的运行,并且不能被阻塞、处理和忽略。 终止
SIGALRM 该信号当一个定时器到时的时候发出。 终止
SIGSTOP 该信号用于暂停一个进程,且不能被阻塞、处理或忽略。 暂停进程
SIGTSTP 该信号用于暂停交互进程,用户可键入SUSP字符(通常是Ctrl-Z)发出这个信号。 暂停进程
SIGCHLD 子进程改变状态时,父进程会收到这个信号 忽略
SIGABORT 该信号用于结束进程 终止
信号相关的api函数
给指定进程发送信号
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
//参数1 ---- 指定的进程ID
pid > 0 , 表示给指定的进程发送信号
pid = 0 , 表示给与当前进程在同一个进程组中的所有进程发送信号
pid = -1, 表示给进程表中所有进程发送信号
//参数2 ---- 要发送的信号
//返回值 ----- 成功:0,失败:-1
例如:
```
int main(int argc,char **argv)
{
pid_t pid;
#if 0
printf("请输入要杀死的进程的PID:");
scanf("%d",&pid);
if(kill(pid,SIGKILL) < 0){
perror("kill");
exit(1);
}
#else
int i = 0;
if((pid = fork()) < 0){
perror("fork");
exit(1);
}else if(!pid){
while(1){
printf("我是子进程!\n");
sleep(1);
i++;
if(i == 7)
//kill(0,SIGKILL);
kill(-1,SIGKILL);
}
}else{
while(1){
printf("我是父进程!\n");
sleep(1);
}
}
#endif
return 0;
}
```
给当前进程发送信号
#include <signal.h>
int raise(int sig);
//参数 ------ 要送的信号
//返回值-----成功:0,失败:-1
例如:
```
int main(int argc,char **argv)
{
int i = 0;
while(1){
printf("我是一只小小鸟!\n");
sleep(1);
i++;
if(i == 7)
raise(SIGKILL);
}
return 0;
}
```
在进程中设置定时器(闹钟)
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
//参数 ----- 要设置秒数,从调用该函数开始计时,进程运行到seconds秒后,内核就会给当前进程发送SIGALRM信号
//返回值 ----- 如果之前有设置过定时器,则返回剩余的秒数,如果没有设置过,则返回0
例如:
```
int main(int argc,char **argv)
{
alarm(7);
#if 1
while(1){
printf("我是一只小小鸟!\n");
sleep(1);
}
#endif
return 0;
}
```
使进程暂停,收到任一信号则返回
#include <unistd.h>
int pause(void);
//返回值 -----成功:进程收到的信息,失败:-1
例如:
```
int main(int argc,char **argv)
{
alarm(7);
printf("设置定时器,7秒后时间到!\n");
pause();
return 0;
}
```
注册信号,设置信号的响应方式
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
//参数1 ----- 要注册的信号
//参数2 ----- 对注册的信号的响应方式:
SIG_IGN:忽略该信号
SIG_DFL:采用系统默认方式处理信号
自定义的信号处理函数指针,信号处理函数类型如下:
void xxxx(int signo)
{
//处理信号的代码
}
//返回值-----成功:信号处理函数的地址,失败:SIG_ERR
例如:
```
void fun(int signo)
{
int i;
for(i = 0; i < 10; i++){
printf("我要出去玩!\n");
sleep(1);
}
}
int main(int argc,char **argv)
{
//signal(SIGALRM,SIG_IGN);
signal(SIGALRM,fun);
alarm(7);
#if 1
while(1){
printf("我要好好学习...!\n");
sleep(1);
}
#endif
return 0;
}
```