栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

信号和管道------初学者入门级

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

信号和管道------初学者入门级

1、进程间通信方式 1.1 进程间通信方式分类

        信号:软中断模拟机制,类似于通知
        管道:可以进行数据传输,具有单向导通性以及阻塞
        共享内存:多个进程共享一块数据,可以随时读取以及更改
        信号量集:同步保护资源
        消息队列:最符合通信思想,单纯收发数据
        套接字:用于网络通信

1.2 为什么要有进程间的通讯

        多任务的操作系统
        资源的共享
        通知事件
        进程控制
        数据的传输

2、管道通信

        他的特点是单向通信。遵循先进先出规则
                首先他有两个端,一端用户写数据,一端用户读数据
                写端只能用来写数据,不能用来读数据
                读端只能用来读数据,不能用来写数据
                并且会发生写阻塞和读阻塞,只有读端和写端同时存在才有意义

2.1 无名管道  pipe

        函数的功能:创建一个无名管道   (无名管道是用于父子间进行通信的)

        函数的头文件:#include

        函数的原型:int pipe(int pipefd);

        函数的参数:int pipefd:用来存放读端和写端的文件描述符的
                              pipefd[0]:读端
                              pipefd[1]:写端

        函数的返回值:成功返回  0                    失败返回     -1

无名管道的特点: 

        ① 只能用于有亲缘关系的进程间通讯,并不会在进程空间产生一个实实在在的管道文件
        ② 数据读出之后就不存在管道中
        ③ 创建无名管道的时候   会直接得到两个文件描述符。有了文件描述符就可以向管道中读取或者是写入内容
        ④ 无名管道有固定的读端和写端。假如管道里没有内容 读取的时候就会阻塞;假如管道写满数据  再往里写数据 也会阻塞                 最多可以写入 65536 个字节

无名管道使用注意事项:

        ① 必须在 fork 函数之前调用 pipe 函数,否则子进程将不会继承文件描述符
        ② 只有在读端存在的时候,向管道写入内容才有意义
        ③ 管道里的数据  假如一直不读取   写满数据就会阻塞
        ④ 父子进程运行的先后顺序不确定,为了保证父进程先执行,可以在子进程中调用 sleep(1) 函数

  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 pid_t pd;
  7 int fd[2];
  8 int main()
  9 {
 10         pipe(fd);    //pipe函数要在fork函数之前,保证父子进程资源相同,在一个管道中
 11         pd=fork();
 12         if(pd<0)
 13         {
 14                 perror("fork");
 15                 return -1;
 16         }
 17         if(pd>0)
 18         {
 19                 close(fd[0]);//关闭父进程的读
 20                 write(fd[1],"father space!",13);//打开父进程的写,要写入的内容,要写入内容的大小
 21                 printf("pipe num1:%dn",pipe(&fd[1]));//打印pipe函数写的返回值,看是否写入成功
 22                 printf("this is father test!n");
 23                 printf("current1 pid:%dn",getpid());//这是父进程中,当前的父进程号
 24         }
 25         else if(pd==0)
 26         {
 27                 char buf[100];//创建一个字符数组,用来存放读取到的内容
 28                 close(fd[1]);//关闭子进程的写
 29                 read(fd[0],buf,15);//打开子进程的读,并将读取到的内容放在buff里,要读取内容的大小
 30                 printf("pipe num2:%dn",pipe(&fd[0]));//打印pipe函数读的返回值,看是否读取成功
 31                 printf("son space welcome:%sn",buf);//子进程获取到父进程中的内容,并打印出来
 32                 printf("current2 pid:%dn",getpid());//这是子进程中,当前的子进程号
 33         }
 34         return 0;
 35 }//输出:
pipe num1:0
this is father test!
current1 pid:3108
pipe num2:0
son space welcome:father space!
current2 pid:3109
2.2 有名管道  mkfifo

        函数功能:创建一个有名管道   (有名管道是可以用于任意进程间进行通信)

        函数的头文件:#include
                                 #include

        函数的原型:int mkfifo(const char *pathname, mode_t mode);

        函数的参数:const char *pathname:要创建的管道的名字(带路径)
                             mode_t mode:创建管道的时候给的权限

        函数的返回值:成功返回  0                        失败返回   -1

 特点:   

        会创建一个真正存在的管道文件,用于任意两个进程间通讯

 注意:
        在有名管道里  读端只能以只读的方式打开文件
                                写端只能以只写的方式打开文件

读端和写端在不同的终端打开,如果有名管道文件已经存在,则需要注释掉创建有名管道的语句。

  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 int main()                                   //这里是写端
  8 {
  9         int ret,fd;
 10 //      ret=mkfifo("./mktest",0777);//创建一个有名管道文件,并赋予它指定的权限,如果已存在,则需注释掉,否则显示文件已存在
 11         if(ret<0)//如果返回值小于零,说明有名管道文件创建失败
 12         {
 13                 perror("mkfifo");
 14                 return -1;
 15         }
 16         if(!access("./mktest",F_OK))//access函数判断文件是否存在,如果存在则返回零,所以要取反
 17         {
 18                 fd=open("./mktest",O_WRONLY);//在写端以只写的方式打开有名管道文件
 19                 write(fd,"hello world!",12);//要写入的内容,及写入内容的大小
 20         }
 21         close(fd);
 22         return 0;
 23 }
  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 int main()                                       //这里是读端
  8 {
  9         char buf[20];            
 10         int ret,fd;
 11 //      ret=mkfifo("./mktest",0777);//创建一个有名管道文件,并赋予它指定的权限,如果已存在,则需注释掉,否则显示文件已存在
 12         if(ret<0)
 13         {
 14                 perror("mkfifo");
 15                 return -1;
 16         }
 17         if(!access("./mktest",F_OK))
 18         {
 19                 fd=open("./mktest",O_RDONLY);//在读端以只读的方式打开有名管道文件
 20                 read(fd,buf,12);//要打开的文件描述符为0,读取到的内容存放在buff里,读取到的字节数
 21                 printf("buf:%sn",buf);//打印出读取到的内容
 22         }
 23         close(fd);
 24         return 0;
 25 }
2.3 删除文件  unlink

        函数功能:删除文件(删除一个有名管道文件)(目录文件无法删除)

        函数的头文件:#include

        函数的原型:int unlink(const char *pathname);

        函数的参数:const char *pathname:要删除的文件的名字(带路径)

        函数的返回值:成功返回  0                        失败返回   -1

  1 #include
  2 #include
  3 int main()
  4 {
  5         unlink("./mktest");//要删除的管道文件名
  6         return 0;
  7 }

普通文件和有名管道文件的区别:

        ①要读取有名管道的内容  必须以O_RDONLY方式打开
        ②要写有名管道时   必须以O_WRONLY方式打开
        ③有名管道里的内容   读取一次之后  就没有了,普通文件读完之后  内容还在

3、信号

信号:是用来通知进程要去干什么。信号就是内核里一个通知的机制,这个机制是一个软中断

中断:就是打断当前正在执行的事情  转而去做另外的事情,另外的事情执行完之后   再回过头来执行之前未执行完的事情。

              先要保护现场(压栈)  另外的事情做完之后  再回过来

              做我没有做完的事  在做这个事之前要做恢复现场(出栈)

信号产生的时机:任意时间

信号的周期

              信号产生

              信号在进程里注册

              信号在进程里注销

              信号处理函数

信号的查看:kill -l

             共有 62 个信号

              2) SIGINT  ctrl+c        杀死进程

              3) SIGQUIT   ctrl+     杀死进程

              9) SIGKILL  kill信号

              14) SIGALRM  时钟信号

信号的相关说明

              32位之前叫做不可靠信号,实时性不好  易丢失

              32位之后位扩充信号,实时性较好   不易丢失

信号的产生有什么手段

              在终端输入ctrl+c ctrl+  kill -9

              内核在产生异常的时候也会发送一个信号

              在进程里可以通过调用kill函数来给另一个进程发送信号

① kill  向指定的进程发送指定的信号  (重要)

        函数功能:向指定的进程发送指定的信号

        函数的头文件:#include

        函数的原型:int kill(pid_t pid, int sig);

        函数的参数:pid_t pid:要给谁发信号(进程号)
                              int sig:要发送的信号(写数字[比如:2]或者信号所对应的宏[比如:SIGINT])

        函数的返回值:成功返回  0                   失败返回   -1

#include
#include
int main()
{

	kill(4082,2);
	return 0;
}
② raise 向进程本身发送信号

        函数功能:向自己发送一个指定的信号

        函数的头文件:#include

        函数的原型:int raise(int sig);

        函数的参数:int sig:要给自己发送的信号

        函数的返回值:成功返回 0                失败返回    -1

  1 #include
  2 #include
  3 int main()
  4 {
  5         printf("hello world!n");
  6         raise(2);//向自己发送一个杀死进程的信号,2号信号
  7         while(1);//死循环
  8 }
③ pause  阻塞一个进程,直到有信号过来为止

        函数功能:阻塞一个进程,直到捕捉到一个信号

        函数的头文件:#include

        函数的原型:int pause(void);

        函数的参数:无

        函数的返回值:-1

  1 #include 
  2 #include 
  3 #include 
  4 #include 
  5 int main()
  6 {
  7         printf("hello world!n");
  8         alarm(2);
  9         pause();
 10         printf("the end!n");
 11         exit(0);
 12 }
④ alarm  设置时间,杀死自己

        函数的功能:设置时间  时间到了之后产生一个14号信号  杀死自己

        函数的头文件:#include

        函数的原型:unsigned int alarm(unsigned int seconds);

        函数的参数:unsigned int seconds:你要定时的秒数

        函数的返回值:假如在调用这个闹钟之前已经设置了闹钟,但是设置的闹钟时间还没到  则返回上个闹钟剩余的时间                                       否则返回 0

  1 #include
  2 #include 
  3 #include 
  4 #include
  5 int main()
  6 {
  7         alarm(5);
  8         sleep(2);
  9         printf("alarm:%dn",alarm(5));
 10         printf("hello world!n");
 11         pause();
 12         printf("end of the test!n");
 13 }//输出:
alarm:3
hello world!
闹钟
⑤ signal  捕捉一个信号并做处理 (重点)

        函数的功能:将信号的处理重新定义

        函数的头文件:#include

        函数的原型:sighandler_t signal(int signum, sighandler_t handler);

        函数的参数:int signum:你要捕捉的信号
                             sighandler_t handler:捕捉到信号之后执行的函数

                        SIG_DFL:代表收到某个信号之后  按默认的处理           比如:signal(2,SIG_DFL);
                        SIG_IGN:忽略这个信号           比如:signal(2,SIG_IGN);

        函数的返回值:成功返回 回调函数的指针                      失败返回  SIG_ERR

  1 #include
  2 #include 
  3 #include 
  4 #include
  5 void myfunc(int signum)
  6 {
  7         printf("i get a signal is:%dn",signum);
  8 }
  9 int main()
 10 {
 11         printf("pid:%dn",getpid());
 12         signal(2,myfunc);
 13         printf("end of the test!n");
 14         while(1);
 15         return 0;
 16 }//输出:
pid:4316
end of the test!
^Ci get a signal is:2
^退出 (核心已转储)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/999045.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号