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

这篇具有很好参考价值的文章主要介绍了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 }

发送端文章来源地址https://www.toymoban.com/news/detail-718637.html

  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 }

到了这里,关于Linux系统编程——进程间通信的学习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux系统】理解Linux中进程间通信

    进程间通信(IPC,Interprocess communication)是一组编程接口,让程序员能够协调不同的进程,使之能在一个操作系统里同时运行,并相互传递、交换信息。这使得一个程序能够在同一时间里处理许多用户的要求。因为即使只有一个用户发出要求,也可能导致一个操作系统中多个

    2023年04月21日
    浏览(36)
  • Linux系统-进程间通信

    本章主要讲解学习Linux中本系统下的进程间通信 概念: 进程间通信简称IPC(Inter process communication),进程间通信就是在不同进程之间传播或交换信息 进程间通信目的: 数据传输:一个进程需要将它的数据发送给另一个进程 资源共享:多个进程之间共享同样的资源 通知事件

    2024年02月05日
    浏览(28)
  • Linux网络编程:socket & fork()多进程 实现clients/server通信

    UNIX网络编程:socket实现client/server通信 随笔简单介绍了TCP Server服务单客户端的socket通信,但是并未涉及多客户端通信。 对于网络编程肯定涉及到多客户端通信和并发编程 (指在同时有大量的客户链接到同一服务器),故本随笔补充这部分知识。 而且并发并发编程涉及到多进程

    2024年02月05日
    浏览(46)
  • 学习系统编程No.20【进程间通信之命名管道】

    北京时间:2023/4/15/10:34,今天起床时间9:25,睡了快8小时,昨天刷视屏刷了一个小时,本来12点的时候发完博客洗把脸就要睡了,可惜,看到了一个标题,说实话,现在的标题党是懂人性的,接下来就是无法自拔的一个小时快乐时光,但导致莫名间接熬夜,你说烦人不烦人!但

    2023年04月17日
    浏览(38)
  • 学习系统编程No.18【进程间通信之管道实战】

    北京时间:2023/4/11/21:17,今天的文章更新啦!但是还是没有上热榜,所以我们需要继续更文啦!我相信下一篇博客肯定是可以上热榜的,加油!并且今天晚上因为有一节体育课,所以导致现在才开始码字,体育课上教我们打羽毛球,虽然我自从高考到现在已经快一年没打了,

    2024年02月02日
    浏览(36)
  • Linux操作系统——第四章 进程间通信

        目录 进程间通信介绍 进程间通信目的 进程间通信发展 进程间通信分类 管道 System V IPC POSIX IPC 管道 什么是管道 匿名管道 管道读写规则 管道特点 命名管道 创建一个命名管道 匿名管道与命名管道的区别 命名管道的打开规则 system V共享内存 共享内存示意图  共享内存数

    2024年02月09日
    浏览(45)
  • Linux学习记录——이십 进程间通信(2)共享内存

    system是一套标准,独立于文件系统之外,是系统专门为通信而设计出来的内核模块,称之为system V的IPC通信机制。 共享内存的主要做法也是让两个毫不相关的进程看到同一份资源。 进程的地址空间内,栈和堆区之间有个共享区,堆是向上增长,栈是向下增长,重合的那个地方

    2023年04月24日
    浏览(39)
  • (25)Linux IPC 进程间通信&&系统调用:pipe接口

    我们在之前讲过 \\\"进程之间是具有独立性\\\" 的,如果进程间想交互数据,成本会非常高! 因为独立性之本质即 \\\"封闭\\\",进程们你封闭你的我封闭我的,那么进程间的交流可谓是窒碍难行。 进程间的通信说白了就是 \\\"数据交互\\\",我们需要多进程进行协同处理一件事情。 刚才说的

    2024年02月02日
    浏览(40)
  • Linux系统编程(终端和进程的关系)

    本篇文章带大家学习终端和进程的关系,终端相信大家都听过,那么真的理解终端是什么吗?应该有很多同学对于终端只是有一个模糊的概念。那么这篇文章就详细的来讲解一下终端的概念。 在Linux系统中,终端(Terminal)和控制台(Console)是两个不同的概念。它们都提供了

    2024年02月11日
    浏览(41)
  • linux【网络编程】TCP协议通信模拟实现、日志函数模拟、守护进程化、TCP协议通信流程、三次握手与四次挥手

    Tcp通信模拟实现与Udp通信模拟实现的区别不大,一个是面向字节流,一个是面向数据报;udp协议下拿到的数据可以直接发送,tcp协议下需要创建链接,用文件描述符完成数据的读写 1.1.1 接口认识 1.1.1.1 listen:监听socket 1.1.1.2 accept:获取连接 通信就用accept返回的文件描述符,

    2024年02月06日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包