进程间通信-信号-pipe-fifo
任务详情
编译运行附件中的代码,提交运行结果截图 理解代码,特别是相关系统调用的使用。
Linux进程间通信
进程是程序运行资源分配的最小单位。每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,Inter-Process Communication)。
运行云班课中的老师所给的代码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; } } }
运行结果如图:
运行云班课中老师所给的代码pipedemo2.c
运行结果如图:
命名管道fifo
fifo简介
FIFO(First In First Out)文件在磁盘上没有数据块,仅仅是内核中一条通道,各进程可以读写从而实现的进程间通信。支持多端读或多端写;
严格遵循先进先出原则;
不支持诸如seek()等文件定位操作;
命名管道fifo
先运行编译testmf.c文件,代码如下:
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> int main() { int res = mkfifo("/tmp/myfifo", 0777); if (res == 0) { printf("FIFO created \n"); } exit(EXIT_SUCCESS); }
编译运行consumer.c和producer.c,
consumer.c代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <limits.h> #include <sys/types.h> #include <sys/stat.h> #define FIFO_NAME "/tmp/myfifo" #define BUFFER_SIZE PIPE_BUF int main() { int pipe_fd; int res; int open_mode = O_RDONLY; char buffer[BUFFER_SIZE + 1]; int bytes = 0; memset(buffer, 0, sizeof(buffer)); printf("Process %d opeining FIFO O_RDONLY \n", getpid()); pipe_fd = open(FIFO_NAME, open_mode); printf("Process %d result %d\n", getpid(), pipe_fd); if (pipe_fd != -1) { do { res = read(pipe_fd, buffer, BUFFER_SIZE); bytes += res; } while (res > 0); close(pipe_fd); } else { exit(EXIT_FAILURE); } printf("Process %d finished, %d bytes read\n", getpid(), bytes); exit(EXIT_SUCCESS); }
producer.c代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <limits.h> #include <sys/types.h> #include <sys/stat.h> #define FIFO_NAME "/tmp/myfifo" #define BUFFER_SIZE PIPE_BUF #define TEN_MEG (1024 * 1024 * 10) int main() { int pipe_fd; int res; int open_mode = O_WRONLY; int bytes = 0; char buffer[BUFFER_SIZE + 1]; if (access(FIFO_NAME, F_OK) == -1) { res = mkfifo(FIFO_NAME, 0777); if (res != 0) { fprintf(stderr, "Could not create fifo %s \n", FIFO_NAME); exit(EXIT_FAILURE); } } printf("Process %d opening FIFO O_WRONLY\n", getpid()); pipe_fd = open(FIFO_NAME, open_mode); printf("Process %d result %d\n", getpid(), pipe_fd); if (pipe_fd != -1) { while (bytes < TEN_MEG) { res = write(pipe_fd, buffer, BUFFER_SIZE); if (res == -1) { fprintf(stderr, "Write error on pipe\n"); exit(EXIT_FAILURE); } bytes += res; } close(pipe_fd); } else { exit(EXIT_FAILURE); } printf("Process %d finish\n", getpid()); exit(EXIT_SUCCESS); }
signal信号
运行云班课中所给代码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"); }
运行结果如图:
运行云班课中所给代码sigdemo2.c:
代码如下:
#include <stdio.h> #include <signal.h> main() { signal( SIGINT, SIG_IGN );//SIG_IGN为默认信号忽略 printf("you can't stop me!\n"); while( 1 ) { sleep(1); printf("haha\n"); } }
运行结果如图:
运行云班课中所给代码sigactdemo.c:
代码如下:
#include <stdio.h> #include <unistd.h> #include <signal.h> #define INPUTLEN 100 void inthandler(); int main() { struct sigaction newhandler;//定义一个sigaction结构体newhandler sigset_t blocked; char x[INPUTLEN]; newhandler.sa_handler = inthandler;//处理中断时调用inthandler()函数。 newhandler.sa_flags = SA_RESTART|SA_NODEFER |SA_RESETHAND; //被阻断时**重新输入**且允许递归调用处理函数,但当处理函数被调用时需要重置才再次有效 sigemptyset(&blocked); sigaddset(&blocked, SIGQUIT); newhandler.sa_mask = blocked; if (sigaction(SIGINT, &newhandler, NULL) == -1) perror("sigaction"); else while (1) { fgets(x, INPUTLEN, stdin); printf("input: %s", x); } return 0; } void inthandler(int s)//中断处理时调用的函数 { printf("Called with signal %d\n", s);//输出这个操作代表的的信号量 sleep(s * 4); printf("done handling signal %d\n", s); }
运行结果如图:
运行云班课所给代码sigactdemo2.c:
代码如下:
#include <unistd.h> #include <signal.h> #include <stdio.h> void sig_alrm( int signo ) { /*do nothing*/ } unsigned int mysleep(unsigned int nsecs) { struct sigaction newact, oldact; unsigned int unslept; newact.sa_handler = sig_alrm; //在内核注册SIGALRM信号的处理函数sig_alrm sigemptyset( &newact.sa_mask );//初始化sa_mask所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含任何有效信号。 newact.sa_flags = 0; //当某个信号的处理函数被调用时候,当前的信号被加入到进程的信号阻塞集,如果想让其他信号也加入到信号阻塞集合就通过sa_mask来说明。 sigaction( SIGALRM, &newact, &oldact );//这里被替换的结构体是oldact,原来的结构体是newact //通过传入newact修改了SIGALRM信号的处理动作,传入oldact读取SIGALRM原来的处理动作 //把SIGALRM对应的编号传入信号处理注册函数(sig_alrm)的参数列表中。 alarm( nsecs ); //在当前进程设定闹钟,时间一到就终止当前进程 pause();//将进程挂起,直到有信号抵达 unslept = alarm ( 0 ); sigaction( SIGALRM, &oldact, NULL ); return unslept; } int main( void ) { while( 1 ) { mysleep( 2 ); printf( "Two seconds passed\n" ); } return 0; }
运行结果如图: