Linux系统编程——进程间通信的学习

学习参考博文:

  1. 进程间的五种通信方式介绍
  2. Linux 信号介绍

Linux系统编程学习相关博文

  1. Linux系统编程——文件编程的学习
  2. Linux系统编程——进程的学习
  3. Linux系统编程——线程的学习
  4. Linux系统编程——网络编程的学习

一、概述

常规学习Linux系统编程的内容是复杂且繁多的,不推荐刚开始接触代码的朋友去学习,所以介绍Linux系统编程的目的主要是以应用开发为主。

进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。

IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC。

1. 无名管道和有名管道的区别

  1. 无名管道是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间),它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。
  2. 有名管道可以在无关的进程之间交换数据,与无名管道不同。

2. 当打开一个FIFO时,是否设置非阻塞标志(O_NONBLOCK)的区别:

  1. 若没有指定O_NONBLOCK(默认),只读 open 要阻塞到某个其他进程为写而打开此 FIFO。类似的,只写 open 要阻塞到某个其他进程为读而打开它。

  2. 若指定了O_NONBLOCK,则只读 open 立即返回。而只写 open 将出错返回 -1 如果没有进程已经为读而打开该 FIFO,其errno置ENXIO。

3. 消息队列

  1. 消息队列,是消息的链接表,存放在内核中。
  2. 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。

4. 共享内存

  1. 共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
  2. 因为多个进程可以同时操作,所以需要进行同步。
  3. 信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。

5. 信号

  1. 每个信号都有一个名字和编号,这些名字都以“SIG”开头,例如“SIGIO ”、“SIGCHLD”等等。
  2. 信号定义在signal.h头文件中,信号名都定义为正整数。
  3. 具体的信号名称可以使用kill -l来查看信号的名字以及序号,信号是从1开始编号的,不存在0号信号。kill对于信号0又特殊的应用。
  4. 信号的处理有三种方法,分别是:忽略、捕捉和默认动作

6. 信号量

信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。

  1. 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
  2. 信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
  3. 每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。(P操作相当于拿钥匙,V操作相当于放钥匙)
  4. 支持信号量组。

二、进程间通信API

在Linux系统中,操作系统提供了一系列的API,详细看下图

1. 管道
创建无名管道		pipe()
创建有名管道		mkfifo()
2. 消息队列
创建或打开消息队列	msgget()
添加消息				msgsnd()
读取消息				msgrcv()
控制消息队列			msgctl()
3. 共享内存
创建或获取共享内存		shmget()
将共享内存映射到当前进程的虚拟地址空间	shmat()
断开与共享内存的连接		shmdt()
控制共享内存的相关信息	shmctl()
4. 信号
信号处理函数		入门版 signal() / 高级版 sigaction()
信号发送函数		入门版 kill() / 高级版 sigqueue()
5. 信号量
创建或获取信号量组		semget()
控制信号量的相关信息		semctl()
对信号量组进行操作		semop()

三、API介绍

1. pipe函数

#include <unistd.h>

int pipe(int pipefd[2]);

1. 函数功能:创建无名管道
2. 形参说明:
pipefd[2]:一个管道建立时,它会创建两个文件描述符:fd[0]为读而打开,fd[1]为写而打开。
3. 返回值:成功返回0,失败返回-1

2. mkfifo函数

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);

1. 函数功能:创建有名管道
2. 形参说明:
pathname:文件路径名
mode:与open函数中的mode相同。一旦创建了一个FIFO,就可以用一般的文件I/O函数去操作它。(忘记的可以去文件编程学习篇章回顾下)
3. 返回值:成功返回0,失败返回-1

3. msgget函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);

1. 函数功能:创建或打开消息队列
2. 形参说明
key:键值key,可自己写死,也可用ftok函数生成(ftok函数具体看API使用例子了解)
msgflg:
 - 这个参数可以是单独的IPC_CREAT,也可以是IPC_CREAT|IPC_EXCL,但IPC_EXCL单独使用没有意义
 - 如果单独使用IPC_CREAT(记得附加权限),或者flg为0:创建一个消息队列,如果创建的消息队列已经存在,则返回已经存在的队列ID,不存在则创建 
 - IPC_CREAT | IPC_EXCL:如果不存在消息队列,则创建,如果已经有了消息队列,则返回-1
3. 返回值:成功返回队列ID,失败返回-1

4. msgsnd函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

1. 函数功能:添加消息
2. 形参说明:
msqid:队列ID
msgp:msgp参数是一个指针,指向调用者定义的结构体,其一般形式如下:
	struct msgbuf {
		long mtype;       /* message type, must be > 0 */
		char mtext[1];    /* message data */
	};
	mtext字段是一个数组(或其他结构),其大小由非负整数值msgsz指定。允许零长度的消息(即没有mtext字段)。mtype字段必须是严格的正整数值。接收进程可以使用此值进行消息选择
msgsz:指定msgp结构体里边mtext参数的大小
msgflg:默认是0
3. 返回值:成功返回0,失败返回-1

5. msgrcv函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

1. 函数功能:读取消息
2. 形参说明:
msqid:队列ID
msgp:msgp参数是一个指针,指向调用者定义的结构体,其一般形式如下:
	struct msgbuf {
		long mtype;       /* message type, must be > 0 */
		char mtext[1];    /* message data */
	};
msgsz:读取数据的大小
msgtyp:mtype字段必须是严格的正整数值。接收进程可以使用此值进行消息选择
msgflg:msgflg参数是一个位掩码,由以下零个或多个标志组合而成:
	· IPC_NOWAIT
	如果队列中没有请求类型的消息,则立即返回
	· MSG_EXCEPT
	当msgtyp大于0时,用于读取消息类型与msgtyp不同的队列中的第一条消息。
	· MSG_NOERROR
	如果消息文本长度超过msgsz字节,则截断消息文本。
	· 为0时是默认状态,当没有消息类型与msgtyp相同的队列发送信息时,则一直阻塞
3. 返回值:成功返回消息数据的长度,失败返回-1

6. msgctl函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf)

1. 函数功能:控制消息队列
2. 形参说明:
msqid:队列ID
cmd:IPC_RMID————从内核中删除消息队列(其他参数请自行查阅)
buf:控制消息队列时数据处理的结构体(默认是NULL)
3. 返回值:成功返回0,失败返回-1

7. shmget函数

#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);

1. 函数功能:创建或获取共享内存
2. 形参说明:
key:键值key,可自己写死,也可用ftok函数生成(ftok函数具体看API使用例子了解)
size:当用shmget函数创建一段共享内存时,必须指定其 size;而如果引用一个已存在的共享内存,则将 size 指定为0 。
shmflg:
	- 这个参数可以是单独的IPC_CREAT,也可以是IPC_CREAT|IPC_EXCL,但IPC_EXCL单独使用没有意义
 	- 如果单独使用IPC_CREAT(记得附加权限),或者flg为0:创建一个共享内存,如果创建的共享内存已经存在,则返回已经存在的共享内存ID,不存在则创建 
 	- IPC_CREAT | IPC_EXCL:如果不存在共享内存,则创建,如果已经有了共享内存,则返回-1
3. 返回值:成功返回共享内存ID,失败返回-1

8. shmat函数

#include <sys/types.h>
#include <sys/shm.h>

void *shmat(int shmid, const void *shmaddr, int shmflg);

1. 函数功能:将共享内存映射到当前进程的虚拟地址空间
2. 形参说明:
shmid:共享内存ID
shmaddr:该参数常用的是NULL。如果shmadr为NULL,系统选择一个合适的(未使用的)地址来附加该段
shmflg:该形参作用是权限附加,常用的是0。如果为0,系统默认映射进来的共享内存为可读可写权限
3. 返回值:成功返回指向共享内存的指针,失败返回-1

9. shmdt函数

#include <sys/types.h>
#include <sys/shm.h>

int shmdt(const void *shmaddr);

1. 函数功能:断开与共享内存的连接
2. 形参说明:
shmaddr:映射后返回共享内存的指针
3. 返回值:成功返回0,失败返回-1

10. shmctl函数

#include <sys/ipc.h>
#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

1. 函数功能:控制共享内存的相关信息
2. 形参说明:
shmid:共享内存ID
cmd:命令参数。常用的是IPC_RMID(从系统中删除该共享内存)
buf:该参数是卸载共享内存后所返回的一些信息。不关心为NULL
3. 返回值:成功返回0,失败返回-1

11. signal函数

#include <signal.h>

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

1. 函数功能:信号处理函数
2. 形参说明:
signum:监听的信号(kill -l参看)
handler:收到信号后处理的函数
	函数原型:typedef void (*sighandler_t)(int);

12. kill函数

#include <sys/types.h>
#include <signal.h>

int kill(pid_t pid, int sig);

1. 函数功能:信号发送函数
2. 形参说明:
pid:发送信号时对方的pid号
sig:要发送的信号(kill -l参看)
3. 返回值:成功返回0,失败返回-1

13. sigaction函数

#include <signal.h>

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

1. 函数功能:信号处理函数(带数据)
2. 形参说明:
signum:监听的信号(kill -l参看)
act:收到信号后处理的函数
	结构体原型:
	struct sigaction {
		void     (*sa_handler)(int);
		void     (*sa_sigaction)(int, siginfo_t *, void *);
		sigset_t   sa_mask;
		int        sa_flags;
		void     (*sa_restorer)(void);
	};
	上面结构体里第二个函数指针第二个struct siginfo结构体的相关信息
	siginfo_t {
		int      si_signo;    /* Signal number */
		int      si_errno;    /* An errno value */
		int      si_code;     /* Signal code */
		int      si_trapno;   /* Trap number that caused
		hardware-generated signal
		(unused on most architectures) */
		pid_t    si_pid;      /* Sending process ID */
		uid_t    si_uid;      /* Real user ID of sending process */
		int      si_status;   /* Exit value or signal */
		clock_t  si_utime;    /* User time consumed */
		clock_t  si_stime;    /* System time consumed */
		sigval_t si_value;    /* Signal value */
		int      si_int;      /* POSIX.1b signal */
		void    *si_ptr;      /* POSIX.1b signal */
		int      si_overrun;  /* Timer overrun count; POSIX.1b timers */
		int      si_timerid;  /* Timer ID; POSIX.1b timers */
		void    *si_addr;     /* Memory location which caused fault */
		int      si_band;     /* Band event */
		int      si_fd;       /* File descriptor */
	}
oldact:该参数是数据备份。默认为NULL
3. 返回值:成功返回0,失败返回-1

14. sigqueue函数

#include <signal.h>

int sigqueue(pid_t pid, int sig, const union sigval value);

1. 函数功能:信号发送函数(带数据)
2. 形参说明:
pid:发送信号时对方的pid号
sig:要发送的信号(kill -l参看)
value:发送的数据
	联合体原型:
	union sigval {
		int   sival_int;
		void *sival_ptr;
	};
3. 返回值:成功返回0,失败返回-1

15. semget函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg);

1. 函数功能:创建或获取一个信号量组
2. 形参说明:
key:键值key,可自己写死,也可用ftok函数生成(ftok函数具体看API使用例子了解)
nsems:信号量个数
semflg:
	- 这个参数可以是单独的IPC_CREAT,也可以是IPC_CREAT|IPC_EXCL,但IPC_EXCL单独使用没有意义
 	- 如果单独使用IPC_CREAT(记得附加权限),或者flg为0:创建一个共享内存,如果创建的共享内存已经存在,则返回已经存在的共享内存ID,不存在则创建 
 	- IPC_CREAT | IPC_EXCL:如果不存在共享内存,则创建,如果已经有了共享内存,则返回-1
3. 返回值:成功返回信号量集ID,失败返回-1

16. semctl函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semctl(int semid, int semnum, int cmd, ...);

1. 函数功能:控制信号量的相关信息
2. 形参说明:
semid:信号量集id
semnum:操控哪个信号量
cmd:命令参数。常用的是SETVAL

这个函数有三个或四个参数,具体取决于cmd。当有四个时,第四个具有类型联合semur调用程序必须按如下方式定义这个联合体:
	union semun {
		int              val;    /* Value for SETVAL */
		struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
		unsigned short  *array;  /* Array for GETALL, SETALL */
		struct seminfo  *__buf;  /* Buffer for IPC_INFO (Linux-specific) */
	};

3. 返回值:失败返回-1

17. semop函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semop(int semid, struct sembuf *sops, unsigned nsops)

1. 函数功能:对信号量组进行操作
2. 形参说明:
semid:信号量集id
sops:sops所指向的数组中的每个nsop元素都指定了要在单个信号量上执行的操作。该结构体的元素类型为struct sembuf,包含以下成员:
	unsigned short sem_num;  /* semaphore number */
	short          sem_op;   /* semaphore operation */
	short          sem_flg;  /* operation flags */
nsops:信号量集个数(决定第二个参数个数)

该函数的使用例子:
	struct sembuf sops[2];
	int semid;
	
	/* Code to set semid omitted */
	
	sops[0].sem_num = 0;        /* Operate on semaphore 0 */
	sops[0].sem_op = 0;         /* Wait for value to equal 0 */
	sops[0].sem_flg = 0;
	
	sops[1].sem_num = 0;        /* Operate on semaphore 0 */
	sops[1].sem_op = 1;         /* Increment value by one */
	sops[1].sem_flg = 0;
	
	if (semop(semid, sops, 2) == -1) {
	perror("semop");
	exit(EXIT_FAILURE);
	}

3. 返回值:成功返回0,失败返回-1

四、API的使用例子

1. pipe函数

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #include <unistd.h>
  6 
  7 int main()
  8 {
  9 //  int pipe(int pipefd[2]);
 10 
 11     int pid = 0;
 12     int fd[2] = {0};
 13     char buf[128] = {0} ;
 14 
 15     if(pipe(fd) == -1){ //创建管道
 16         printf("create pipe failed\n");
 17         perror("why");
 18     }
 19 
 20     pid = fork(); //创建子进程
 21 
 22     if(pid < 0){ 
 23         printf("create child failed\n");
 24         perror("why");
 25     }
 26     else if(pid > 0){ //父进程
 27         sleep(1);
 28 
 29         printf("This is father\n");
 30         close(fd[0]); //关闭读端
 31         write(fd[1], "Hello World", strlen("Hello World")); //写入数据
 32 
 33         wait(NULL);
 34     }
 35     else{ //子进程
 36         printf("This is child\n");
 37         close(fd[1]); //关闭写端
 38         read(fd[0], buf, sizeof(buf)); //读取数据
 39         printf("read data: %s\n", buf);
 40 
 41         exit(0);
 42     }
 43 
 44     return 0;
 45 }

2. mkfifo函数

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #include <sys/types.h>
  6 #include <sys/stat.h>
  7 #include <errno.h>
  8 #include <fcntl.h>
  9 
 10 int main()
 11 {
 12 //  int mkfifo(const char *pathname, mode_t mode);
 13     int fd = 0;
 14 
 15     if((mkfifo("./file", 0600) == -1) && errno != EEXIST){ //创建管道
 16         printf("create failed\n");
 17         perror("why");
 18     }
 19 
 20     fd = open("./file", O_RDONLY);
 21 
 22     return 0;
 23 }

3. msgget、msgsnd、msgrcv、msgctl函数

接收端demo

  1 #include <stdio.h>
  2 #include <errno.h>
  3 #include <string.h>
  4 #include <stdlib.h>
  5 
  6 #include <sys/types.h>
  7 #include <sys/ipc.h>
  8 #include <sys/msg.h>
  9 
 10 // 1. int msgget(key_t key, int msgflg);
 11 // 2. int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
 12 // 3. ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
 13 
 14 struct msgbuf {
 15     long mtype;       /* message type, must be > 0 */
 16     char mtext[128];    /* message data */
 17 }
 18 
 19 int main()
 20 {
 21     int msgId;
 22 
 23     key_t key;
 24 
 25     struct msgbuf readBuf;
 26     struct msgbuf sendBuf = {988, "Welcome your coming"};
 27 
 28     key = ftok(".", 23); //获取key
 29     printf("key = 0x%x\n", key);
 30 
 31     msgId = msgget(key, IPC_CREAT|0777); //创建消息队列
 32 
 33     if(msgId == -1){
 34         printf("creat quene failed\n");
 35         perror("why");
 36     }
 37 
 38     msgrcv(msgId, &readBuf, sizeof(readBuf.mtext), 888, 0); //读取消息
 39     printf("get message from quene, content: %s\n", readBuf.mtext);
 40 
 41     msgsnd(msgId, &sendBuf, sizeof(sendBuf.mtext), 0); //发送消息
 42 
 43     msgctl(msgId, IPC_RMID, NULL); //删除消息队列
 44 
 45     return 0;
 46 }

发送端

  1 #include <stdio.h>
  2 #include <errno.h>
  3 #include <string.h>
  4 #include <stdlib.h>
  5 
  6 #include <sys/types.h>
  7 #include <sys/ipc.h>
  8 #include <sys/msg.h>
  9 
 10 // 1. int msgget(key_t key, int msgflg);
 11 // 2. int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
 12 // 3. ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
 13 
 14 struct msgbuf {
 15     long mtype;       /* message type, must be > 0 */
 16     char mtext[128];    /* message data */
 17 };
 18 
 19 int main()
 20 {
 21     int msgId;
 22 
 23     key_t key;
 24 
 25     struct msgbuf readBuf;
 26     struct msgbuf sendBuf = {888, "This is content from quene"};
 27 
 28     key = ftok(".", 23); //获取key
 29     printf("key = 0x%x\n", key);
 30 
 31     msgId = msgget(key, IPC_CREAT|0777); //创建消息队列
 32 
 33     if(msgId == -1){
 34         printf("creat quene failed\n");
 35         perror("why");
 36     }
 37 
 38     msgsnd(msgId, &sendBuf, sizeof(sendBuf.mtext), 0); //发送消息
 39     printf("Send over!\n");
 40 
 41     msgrcv(msgId, &readBuf, sizeof(readBuf.mtext), 988, 0); //读取消息
 42     printf("get message from msgGet, content: %s\n", readBuf.mtext);
 43 
 44     msgctl(msgId, IPC_RMID, NULL);
 45 
 46     return 0;
 47 }

4. shmget、shmat、shmdt、shmctl函数

接收端

   1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #include <sys/ipc.h>
  6 #include <sys/shm.h>
  7 #include <sys/types.h>
  8 
  9 // 1. int shmget(key_t key, size_t size, int shmflg);
 10 // 2. void *shmat(int shmid, const void *shmaddr, int shmflg);
 11 // 3. int shmdt(const void *shmaddr);
 12 // 4. int shmctl(int shmid, int cmd, struct shmid_ds *buf);
 13 
 14 int main()
 15 {
 16     int shmid;
 17     char *shmaddr;
 18 
 19     key_t key;
 20 
 21     key = ftok(".", 1); //获取key
 22 
 23     shmid = shmget(key, 1024*4, 0); //获取共享内存
 24 
 25     shmaddr = shmat(shmid, NULL, 0); //映射
 26 
 27     printf("read: %s\n", shmaddr);
 28 
 29     shmdt(shmaddr); //断开共享内存
 30 
 31     printf("quit\n");
 32 
 33     return 0;
 34 }

发送端

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #include <sys/ipc.h>
  6 #include <sys/shm.h>
  7 #include <sys/types.h>
  8 
  9 // 1. int shmget(key_t key, size_t size, int shmflg);
 10 // 2. void *shmat(int shmid, const void *shmaddr, int shmflg);
 11 // 3. int shmdt(const void *shmaddr);
 12 // 4. int shmctl(int shmid, int cmd, struct shmid_ds *buf);
 13 
 14 int main()
 15 {
 16     int shmid;
 17     char *shmaddr;
 18 
 19     key_t key;
 20 
 21     key = ftok(".", 1); //获取key
 22 
 23     shmid = shmget(key, 1024*4, IPC_CREAT|0666); //创建共享内存
 24 
 25     if(shmid == -1){
 26         perror("create shm failed");
 27         exit(-1);
 28     }
 29 
 30     shmaddr = shmat(shmid, NULL, 0); //映射
 31 
 32     strcpy(shmaddr, "Hello World"); //写入数据
 33     printf("write..\n");
 34     sleep(5);
 35 
 36     shmdt(shmaddr); //断开共享内存
 37 
 38     shmctl(shmid, IPC_RMID, NULL); //删除共享内存
 39 
 40     printf("quit\n");
 41 
 42     return 0;
 43 }

5. signal函数

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #include <signal.h>
  6 
  7 // typedef void (*sighandler_t)(int);
  8 // 1. sighandler_t signal(int signum, sighandler_t handler);
  9 
 10 void handler(int signum) //处理函数
 11 {
 12     switch(signum){
 13         case 2:
 14             printf("signum = %d\n", signum);
 15             printf("never quit\n");
 16 
 17             break;
 18         case 9:
 19             printf("signum = %d\n", signum);
 20             printf("never quit\n");
 21 
 22             break;
 23         case 10:
 24             printf("signum = %d\n", signum);
 25             printf("never quit\n");
 26 
 27             break;
 28         default:
 29             printf("signum = %d\n", signum);
 30             printf("never quit\n");
 31 
 32             break;
 33     }
 34 }
 35 
 36 int  main()
 37 {
 38     signal(SIGHUP, handler); //捕获SIGHUP信号
 39     signal(SIGINT, handler); //捕获SIGINT信号
 40     signal(SIGKILL, handler); //捕获SIGKILL信号
 41     signal(SIGUSR1, handler); //捕获SIGUSR1信号
 42 
 43     while(1);
 44 
 45     return 0;
 46 }

6. kill函数

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #include <signal.h>
  6 #include <sys/types.h>
  7 
  8 // typedef void (*sighandler_t)(int);
  9 // 1. sighandler_t signal(int signum, sighandler_t handler);
 10 // 2. int kill(pid_t pid, int sig);
 11 
 12 int  main(int argc, char **argv)
 13 {
 14     int pid;
 15     int signum;
 16     char cmd[32] = "/0";
 17 
 18     if(argc < 3){
 19         printf("please input three param\n");
 20         exit(-1);
 21     }
 22 
 23     signum = atoi(argv[1]); //将字符串转换成整型数(第二个参数)
 24     pid = atoi(argv[2]); //将字符串转换成整型数(第三个参数)
 25 
 26     sprintf(cmd, "kill -%d %d", signum, pid);
 27     //kill(pid, signum); //发送指令
 28 
 29     system(cmd); //发送指令
 30 
 31     return 0;
 32 }

7. sigaction函数

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #include <sys/types.h>
  6 #include <unistd.h>
  7 #include <signal.h>
  8 
  9 // 1. int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
 10 
 11 void handler(int signum, siginfo_t *info, void *context) //处理函数
 12 {
 13     printf("\nsignum = %d\n", signum);
 14 
 15     if(context != NULL){
 16         printf("get data: %d\n", info->si_int);
 17         printf("get data: %d\n", info->si_value.sival_int);
 18         printf("from: %d\n",info->si_pid);
 19     }
 20 }
 21 
 22 int main()
 23 {
 24     struct sigaction act;
 25 
 26     printf("pid = %d\n", getpid());
 27 
 28     act.sa_sigaction = handler;
 29     act.sa_flags = SA_SIGINFO; //如果在sa_flags中指定了SA SIGINFO,则sa _sigaction(而不是sa_handler)指定signum的信号处理函数。
 30 
 31     sigaction(SIGUSR1, &act, NULL); 捕获SIGUSR1信号
 32 
 33     while(1);
 34 
 35     return 0;
 36 }

8. sigqueue函数

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #include <sys/types.h>
  6 #include <unistd.h>
  7 #include <signal.h>
  8 
  9 // 1. int sigqueue(pid_t pid, int sig, const union sigval value);
 10 
 11 int main(int argc, char **argv)
 12 {
 13     int pid;
 14     int signum;
 15 
 16     pid = atoi(argv[2]); //将字符串转换成整型数(第三个参数)
 17     signum = atoi(argv[1]); //将字符串转换成整型数(第二个参数)
 18 
 19     union sigval value;
 20     value.sival_int = 100; //发送的整形数据
 21 
 22     sigqueue(pid, signum, value); //发送函数
 23 
 24     printf("pid = %d\n", getpid()); //打印pid号
 25 
 26     return 0;
 27 }

9. semget、semctl、semop函数

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #include <sys/types.h>
  6 #include <sys/ipc.h>
  7 #include <sys/sem.h>
  8 #include <unistd.h>
  9 
 10 // 1. int semget(key_t key, int nsems, int semflg);
 11 // 2. int semctl(int semid, int semnum, int cmd, ...);
 12 // 3. int semop(int semid, struct sembuf *sops, unsigned nsops);
 13 
 14 union semun {
 15     int              val;    /* Value for SETVAL */
 16     struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
 17     unsigned short  *array;  /* Array for GETALL, SETALL */
 18     struct seminfo  *__buf;  /* Buffer for IPC_INFO
 19                                 (Linux-specific) */
 20 };
 21 
 22 void pGetKey(int semid) //拿钥匙
 23 {
 24     struct sembuf sop;
 25 
 26     sop.sem_num = 0;        /* Operate on semaphore 0 */
 27     sop.sem_op = -1;        /* Wait for value to equal 0 */
 28     sop.sem_flg = SEM_UNDO;
 29 
 30     semop(semid, &sop, 1); //操作信号量
 31 
 32     printf("Get key\n");
 33 }
 34 
 35 void vPutBackKey(int semid) //放钥匙
 36 {
 37     struct sembuf sop;
 38 
 39     sop.sem_num = 0;        /* Operate on semaphore 0 */
 40     sop.sem_op = 1;        /* Wait for value to equal 0 */
 41     sop.sem_flg = SEM_UNDO;
 42 
 43     semop(semid, &sop, 1); //操作信号量
 44 
 45     printf("Put back key\n");
 46 }
 47 
 48 int main()
 49 {
 50     int pid;
 51     int semid;
 52     key_t key;
 53 
 54     union semun value;
 55 
 56     key = ftok(".", 23); //获取key
 57 
 58     //创建/获取一个信号量
 59     semid = semget(key, 1, IPC_CREAT|0666); //创建信号量集
 60 
 61     value.val = 0; //初始时盒子里没钥匙
 62 
 63     //控制信号量集
 64     semctl(semid, 0, SETVAL, value); //信号量集初始化
 65 
 66     pid = fork(); //创建子进程
 67 
 68     if(pid > 0){ //父进程
 69         // 拿钥匙——如果盒子里没钥匙,父进程出于阻塞状态
 70         pGetKey(semid); //拿钥匙
 71         printf("This is father\n");
 72         // 放钥匙
 73         vPutBackKey(semid); //放钥匙
 74     }
 75     else if(pid == 0){ //子进程
 76         printf("This is child\n");
 77         // 放钥匙——因初始化时盒子里没钥匙,无论是不是父进程先运行它都会处于阻塞状态,等子进程把放入钥匙后父进程才能拿钥匙开门
 78         vPutBackKey(semid); //放钥匙
 79     }
 80     else{
 81         printf("fork error\n");
 82     }
 83 
 84     return 0;
 85 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值