1、进程概念;2、进程的控制:(1)生成一个进程:fork(2)进程的同步:wait waitpid(3)进程的退出:exit _exit(4)进程“脱胎换骨”:exec函数族3、进程通信(1)进程为什么需要通信?(2)linux下进程如何通信●早期的unix通信方式无名管道;有名管道;信号●sysem v的通信方式:共享内存、消息队列、信号量●BSD的通信方式:socket4、无名管道:适用于有血缘关系进程通信小任务1:父进程通过无名管道向子进程发送字符串“Hello,you man!”,子进程接收到后显示出来,然后子进程退出,最后父进程退出。
(1)创建子进程:fork(2)创建管道#include <unistd.h>int pipe(int pipefd[2]);参数说明(当管道创建成功后):pipefd[0]:读端的文件描述符;pipefd[1]:写端的文件描述返回值:0表示创建成功,-1表示创建失败(3)父亲写管道write(4)儿子读管道read(5)父亲等待儿子退出wait参考代码:#include <unistd.h>#include <stdio.h>#include <fcntl.h>#include <sys/types.h>#include <string.h>int main(){int pid;int pipefd[2];int ret;char buf[]="Hello,young man!";ret=pipe(pipefd);//创建管道(1)if(ret<0){perror("Failed to create pipe:");return -1;}pid=fork();//能够把(1)语句放此注释的下一样??if(pid<0){perror("Failed to create child process:");return -1;}if(pid>0){close(pipefd[0]);//父进程中关闭无关的读端write(pipefd[1],buf,strlen(buf));wait(NULL);printf("Parent process exit!\n");}else{char receive_buf[100];int count;close(pipefd[1]);//子进程中关闭无关的写端count=read(pipefd[0],receive_buf,100);if(count>0){receive_buf[count]='\0';printf("Child process receive a string:%s\n",receive_buf);}printf("Child process exit!\n");}return 0;}5、有名管道(fifo)(1)文件系统中可见,可以通过mkfifo 命令来创建一个有名管道eg: mkfifo -m 0666 myfifo(2)有名管道的使用跟普通文件一样:open read write close,不用使用lseek!!!!任务2:进程1通过有名管道把键盘输入字符串发送给进程2,进程2收到后显示出来,当收到字符串“exit”是退出程序!!(1)手工建立一个有名管道myfifo(2)打开管道;(3)读写管道注意:有名管道的读写跟普通文件没有什么区别!!参考代码://fifoReader.c#include <unistd.h>#include <stdio.h>#include <fcntl.h>#include <sys/types.h>#include <string.h>int main(){int fd;char buf[128];fd=open("/home/gec/myfifo",O_RDONL Y);if(fd<0){perror("Failed to open fifo:");return -1;}while(1){int count;count=read(fd,buf,127);if(count>0){buf[count]=0;printf("fifoReader receive a string:%s\n",buf);}if(strncmp(buf,"exit",4)==0){break;}}close(fd);return 0;}//fifoWrite.c#include <unistd.h>#include <stdio.h>#include <fcntl.h>#include <sys/types.h>#include <string.h>int main(){int fd;char buf[128];fd=open("/home/gec/myfifo",O_WRONL Y);if(fd<0){perror("Failed to open fifo:");return -1;}while(1){fgets(buf,128,stdin);write(fd,buf,strlen(buf));if(strncmp(buf,"exit",4)==0){break;}}close(fd);return 0;}6、信号(1)可以用命令kill -l列出当前系统所支持的信号(2)对于很多信号,进程都有默认的处理方式;(3)信号的发送#include <sys/types.h>#include <signal.h>int kill(pid_t pid, int sig);(4)信号的处理:当进程接收一个信号后如何与“一段代码关联起来”模版://信号处理函数void 你自己命名的信号处理函数名(int sig)//sig:信号值{//对信号的处理}//在程序的某一个地方把信号处理函数和信号关联起来,其“后果”就是进程一旦接收到该信号,就会导致该信号处理函数的调用!!#include <signal.h>typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);在需要关联的时候只需要调用signal函数就可以了!!信号:signum--------------------信号处理函数:handler小任务3:用触发信号的方式每2秒钟向屏幕打印“Hello,world!”(1)每隔2秒钟触发一个闹钟信号SIGALRMalarm(2);(2)在信号处理函数里完成屏幕大打印:void alarm_handler(int sig){if(sig==SIGALRM){printf(“Hello,world!\n”);\alarm(2);}}(3)在你的程序的某个地方添加如下语句signal(SIGALRM, alarm_handler);参考代码:#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <signal.h>void alarm_handler(int sig){if(sig==SIGALRM){printf("Hello,world!\n");alarm(2);}}int main(){signal(SIGALRM,alarm_handler);//此语句的作用:一旦进程接收到SIGALRM信号,就会导致alarm_handler的调用alarm(2);//此语句的作用:2秒钟后会向调用进程发送SIGALRM信号while(1);return 0;}小任务4:(练习kill的使用)当进程2收到进程1发出的SIGUSR1信号后停止向屏幕输出“Hello,world!\n”. 进程2的执行格式可以如下:./进程1 进程2的进程号参考代码//p1.c#include <stdio.h>#include <unistd.h>#include <signal.h>#include <stdlib.h>int main(int argc,char **argv){int dest_id;int ret;if(argc<2){printf("Argument too few!\n");return 0;}dest_id=atoi(argv[1]);//将参数指针型转换成整型;//sscanf(argv[1],"%d",&dest_id);也可用这个语句实现数据类型转化;printf("The pid of destination process id %d\n",dest_id);ret=kill(dest_id,SIGUSR1);if(ret<0)printf("Failed to send signal.\n");return 0;}//p2.c#include <stdio.h>#include <unistd.h>#include <signal.h>int flag=1;void sigusr1_handler(int sig){if(sig==SIGUSR1){flag=0;}}int main(){signal(SIGUSR1,sigusr1_handler);建立与信号相关联的回调函数关系;while(flag==1){printf("Hello,world!\n");sleep(2);}return 0;}7、共享内存8、共享内存使用的步骤(1)创建共享内存块的一个外键#include <sys/types.h>#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);注意:pathname必须是系统中真实存在的而且稳定的路径,一般proj_id用一个ascii字符来代替(2)获取或者创建共享内存块#include <sys/ipc.h>#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);注意:第一个参数一般为在步骤1所创建或获取的外键,如果你的共享内存块是一个私有共享内存块,可以选择为IPC_PRIV ATE;第二个参数为所创建或获取的共享内存块的大小(以字节为单位);第三个参数所为所创建或获取共享内存块的权限:IPC_CREAT: 当用key所对应共享内存不存在时则创建它;IPC_EXCL:当空享内存块存在则创建失败;0666:共享内块的权限;该函数的返回值,当创建成功是为共享内存块的内部标识!(3)共享内存块的映射#include <sys/types.h>#include <sys/shm.h>void *shmat(int shmid, const void *shmaddr, int shmflg);把shmid所标识的共享内存块映射调用进程的地址空间,第2、3参数一般为0;当映射成功是返回共享内存块在用户空间地址,失败则为-1;(3)撤销共享内存块的映射#include <sys/types.h>#include <sys/shm.h>int shmdt(const void *shmaddr);当进程不需要对共享内存块进行读写的时候调用该函数!!(4)删除共享内存块#include <sys/ipc.h>#include <sys/shm.h>int shmctl(int shmid, int cmd, struct shmid_ds *buf);一般的调用格式:shmctl(shmid,IPC_RMID,NULL);小任务:进程1把从键盘获取的字符串通过共享内存发送给进程2,进程接手后显示出来,当接收到”exit”时退出。