进程间通信-信号-pipe-fifo
进程间通信-信号-pipe-fifo
Linux进程间通信
进程是程序运行资源分配的最小单位。每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,Inter-Process Communication)。
使用man 2 pipe
查看pipe的系统调用:
可知pipe(fd[2])
可表示一个管道,头文件为#include <fcntl.h>
和#include <unistd.h>
pipe的功能:
pipe举例:
1、hello.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#define MAXLINE 80
int main(void)
{
int n;
int fd[2];
pid_t pid;
char line[MAXLINE];
if (pipe(fd) < 0)//如果管道的文件描述符小于0
{
perror("pipe");
exit(1);
}
if ((pid = fork()) < 0)//子进程如果创建成功了,返回的pid值一定大于0
{
perror("fork");
exit(1);
}
if (pid > 0)
{ /* parent */
close(fd[0]);
write(fd[1], "hello world\n", 12);
wait(NULL);
}
else
{ /* child */
close(fd[1]);
n = read(fd[0], line, MAXLINE);
write(STDOUT_FILENO, line, n);
}
return 0;
}
2、pipedemo.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
int len, i, apipe[2];//两个文件描述符
char buf[BUFSIZ];//长度为BUFSIZ
if ( pipe ( apipe ) == -1 ){
perror("could not make pipe");
exit(1);
}
printf("Got a pipe! It is file descriptors: { %d %d }\n",
apipe[0], apipe[1]);
while ( fgets(buf, BUFSIZ, stdin) ){//从输入端获取字符,存入buf数组中
len = strlen( buf );
if ( write( apipe[1], buf, len) != len ){//apipe[1]是写入端,这里write()函数将buf指针指向的内存的len长个字节写入到apipe[1]所指向的管道缓冲区中。
perror("writing to pipe");
break;
}
for ( i = 0 ; i<len ; i++ )
buf[i] = 'X' ;
len = read( apipe[0], buf, BUFSIZ ) ;
if ( len == -1 ){
perror("reading from pipe");
break;
}
if ( write( 1, buf,len ) != len ){
perror("writing to stdout");
break;
}
}
}
3、pipedemo2.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define CHILD_MESS "I want a cookie\n"
#define PAR_MESS "testing..\n"
#define oops(m,x) { perror(m); exit(x); }
main()
{
int pipefd[2];
int len;
char buf[BUFSIZ];
int read_len;
if ( pipe( pipefd ) == -1 )
oops("cannot get a pipe", 1);
switch( fork() ){
case -1:
oops("cannot fork", 2);
case 0:
len = strlen(CHILD_MESS);
while ( 1 ){
if (write( pipefd[1], CHILD_MESS, len) != len )
oops("write", 3);
sleep(5);
}
default:
len = strlen( PAR_MESS );
while ( 1 ){
if ( write( pipefd[1], PAR_MESS, len)!=len )
oops("write", 4);
sleep(1);
read_len = read( pipefd[0], buf, BUFSIZ );
if ( read_len <= 0 )
break;
write( 1 , buf, read_len );
}
}
}
pipe管道的局限性
- 只支持单向数据流
- 只能用于具有亲缘关系的进程之间
- 没有名字,不方便操作
- 管道的缓冲区大小有限
命名管道fifo
fifo简介
FIFO(First In First Out)文件在磁盘上没有数据块,仅仅是内核中一条通道,各进程可以读写从而实现的进程间通信。支持多端读或多端写;
严格遵循先进先出原则;
不支持诸如seek()等文件定位操作;
我们输入 man -k pipe | grep named
实现fifo通信
我们首先需要用mkfifo myfifo
生成一个fifo文件用于两个进程之间的通信
然后在同一个目录下创建两个程序文件:
1、wr.c:
// file: wr.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd, ret, i = 0;
char buf[256];
fd = open("myfifo", O_WRONLY);
if(fd < 0)
{
perror("open error");
}
printf("write start!\n");
while(i < 100)
{
snprintf(buf, 256, "hello %d\n", i);
ret = write(fd, buf, strlen(buf));
if(ret < 0)
{
perror("write error");
}
printf("write ok: %d\n", i);
i++;
sleep(1);
}
return 0;
}
编译所给的consumer.c和producer.c代码,运行结果如下:
signal信号
signal理解
我们先来理解以下signal.h这个函数:
1、sigdemo1.c:
#include <stdio.h>
#include <signal.h>
void f(int);
int main()
{
int i;
signal( SIGINT, f );
for(i=0; i<5; i++ ){
printf("hello\n");
sleep(2);
}
return 0;
}
void f(int signum)
{
printf("OUCH!\n");
}
2、sigdemo2.c:
3、 sigactdemo.c:
4、sigactdemo2.c: