进程间通信-信号-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管道的局限性

  1. 只支持单向数据流
  2. 只能用于具有亲缘关系的进程之间
  3. 没有名字,不方便操作
  4. 管道的缓冲区大小有限

命名管道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:

posted @ 2022-11-13 21:41  少管我  阅读(16)  评论(0编辑  收藏  举报