Linux-进程间通信

Linux-进程间通信

  1. 管道
  2. 消息队列
  3. 信号
  4. 共享内存模型和信号量

管道

a. 匿名管道

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 1. 管道是父子进程间的通信
// 2. fd[0] 代表读;fd[1] 代表写。一般是子进程写,即:先关闭fd[0],在写入fd[1]。父进程读,即:先关闭fd[1],读取fd[0]
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main(int argc, char *argv[])
{
int fds[2];
if (pipe(fds) == -1)
perror("pipe error");

pid_t pid;
pid = fork();
if (pid == -1)
perror("fork error");

if (pid == 0){
close(fds[0]);
char msg[] = "hello world";
write(fds[1], msg, strlen(msg) + 1);
close(fds[1]);
exit(0);
} else {
close(fds[1]);
char msg[128];
read(fds[0], msg, 128);
close(fds[0]);
printf("message : %s\n", msg);
return 0;
}
}

管道1

b. linux 管道原理 (ps -ef|grep 进程|awk ‘{print $2}’|xargs kill -9)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 控制台标准输入转化成标准输出 写入到fd[1]端,另一个进程标准输入来自fd[0]端

#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main(int argc, char *argv[])
{
int fds[2];
if (pipe(fds) == -1)
perror("pipe error");

pid_t pid;
pid = fork();
if (pid == -1)
perror("fork error");

if (pid == 0){
dup2(fds[1], STDOUT_FILENO);
close(fds[1]);
close(fds[0]);
execlp("ps", "ps", "-ef", NULL);
} else {
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
close(fds[1]);
execlp("grep", "grep", "systemd", NULL);
}

return 0;
}

管道1

消息队列

a. ipcs -q 就能看到上面我们创建的消息队列对象。
b. msgget 函数创建消息队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>


int main() {
int messagequeueid;
key_t key;


if((key = ftok("/root/messagequeue/messagequeuekey", 1024)) < 0)
{
perror("ftok error");
exit(1);
}


printf("Message Queue key: %d.\n", key);


if ((messagequeueid = msgget(key, IPC_CREAT|0777)) == -1)
{
perror("msgget error");
exit(1);
}


printf("Message queue id: %d.\n", messagequeueid);
}

c. msgsnd发送msg到消息队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <getopt.h>
#include <string.h>


struct msg_buffer {
long mtype;
char mtext[1024];
};


int main(int argc, char *argv[]) {
int next_option;
const char* const short_options = "i:t:m:";
const struct option long_options[] = {
{ "id", 1, NULL, 'i'},
{ "type", 1, NULL, 't'},
{ "message", 1, NULL, 'm'},
{ NULL, 0, NULL, 0 }
};

int messagequeueid = -1;
struct msg_buffer buffer;
buffer.mtype = -1;
int len = -1;
char * message = NULL;
do {
next_option = getopt_long (argc, argv, short_options, long_options, NULL);
switch (next_option)
{
case 'i':
messagequeueid = atoi(optarg);
break;
case 't':
buffer.mtype = atol(optarg);
break;
case 'm':
message = optarg;
len = strlen(message) + 1;
if (len > 1024) {
perror("message too long.");
exit(1);
}
memcpy(buffer.mtext, message, len);
break;
default:
break;
}
}while(next_option != -1);


if(messagequeueid != -1 && buffer.mtype != -1 && len != -1 && message != NULL){
if(msgsnd(messagequeueid, &buffer, len, IPC_NOWAIT) == -1){
perror("fail to send message.");
exit(1);
}
} else {
perror("arguments error");
}

return 0;
}

d. msgrcv接受消息队列消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <getopt.h>
#include <string.h>


struct msg_buffer {
long mtype;
char mtext[1024];
};


int main(int argc, char *argv[]) {
int next_option;
const char* const short_options = "i:t:";
const struct option long_options[] = {
{ "id", 1, NULL, 'i'},
{ "type", 1, NULL, 't'},
{ NULL, 0, NULL, 0 }
};

int messagequeueid = -1;
struct msg_buffer buffer;
long type = -1;
do {
next_option = getopt_long (argc, argv, short_options, long_options, NULL);
switch (next_option)
{
case 'i':
messagequeueid = atoi(optarg);
break;
case 't':
type = atol(optarg);
break;
default:
break;
}
}while(next_option != -1);


if(messagequeueid != -1 && type != -1){
if(msgrcv(messagequeueid, &buffer, 1024, type, IPC_NOWAIT) == -1){
perror("fail to recv message.");
exit(1);
}
printf("received message type : %d, text: %s.", buffer.mtype, buffer.mtext);
} else {
perror("arguments error");
}

return 0;
}

信号

a. 信号值位于SIGRTMIN(=32)和SIGRTMAX(=63)之间的信号都是可靠信号,其他为不可靠信号
b. 信号注册与使用
信号

c. 信号在操作系统中处理流程
信号在操作系统中处理流程

共享内存模型和信号量

a. 通过程序创建的共享内存和信号量集合,我们可以通过命令 ipcs 查看。当然,我们也可以通过 ipcrm 进行删除。
b. 共享内存与信号量初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <string.h>

#define MAX_NUM 128

struct shm_data {
int data[MAX_NUM];
int datalength;
};

union semun {
int val;
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
};

int get_shmid(){
int shmid;
key_t key;

if((key = ftok("/root/sharememory/sharememorykey", 1024)) < 0){
perror("ftok error");
return -1;
}

shmid = shmget(key, sizeof(struct shm_data), IPC_CREAT|0777);
return shmid;
}

int get_semaphoreid(){
int semid;
key_t key;

if((key = ftok("/root/sharememory/semaphorekey", 1024)) < 0){
perror("ftok error");
return -1;
}

semid = semget(key, 1, IPC_CREAT|0777);
return semid;
}

int semaphore_init (int semid) {
union semun argument;
unsigned short values[1];
values[0] = 1;
argument.array = values;
return semctl (semid, 0, SETALL, argument);
}

int semaphore_p (int semid) {
struct sembuf operations[1];
operations[0].sem_num = 0;
operations[0].sem_op = -1;
operations[0].sem_flg = SEM_UNDO;
return semop (semid, operations, 1);
}

int semaphore_v (int semid) {
struct sembuf operations[1];
operations[0].sem_num = 0;
operations[0].sem_op = 1;
operations[0].sem_flg = SEM_UNDO;
return semop (semid, operations, 1);
}

c. 生成者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "share.h"

int main() {
void *shm = NULL;
struct shm_data *shared = NULL;
int shmid = get_shmid();
int semid = get_semaphoreid();
int i;

shm = shmat(shmid, (void*)0, 0);
if(shm == (void*)-1){
exit(0);
}
shared = (struct shm_data*)shm;
memset(shared, 0, sizeof(struct shm_data));
semaphore_init(semid);
while(1){
semaphore_p(semid);
if(shared->datalength > 0){
semaphore_v(semid);
sleep(1);
} else {
printf("how many integers to caculate : ");
scanf("%d",&shared->datalength);
if(shared->datalength > MAX_NUM){
perror("too many integers.");
shared->datalength = 0;
semaphore_v(semid);
exit(1);
}
for(i=0;i<shared->datalength;i++){
printf("Input the %d integer : ", i);
scanf("%d",&shared->data[i]);
}
semaphore_v(semid);
}
}
}

d. 消费者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

#include "share.h"

int main() {
void *shm = NULL;
struct shm_data *shared = NULL;
int shmid = get_shmid();
int semid = get_semaphoreid();
int i;

shm = shmat(shmid, (void*)0, 0);
if(shm == (void*)-1){
exit(0);
}
shared = (struct shm_data*)shm;
while(1){
semaphore_p(semid);
if(shared->datalength > 0){
int sum = 0;
for(i=0;i<shared->datalength-1;i++){
printf("%d+",shared->data[i]);
sum += shared->data[i];
}
printf("%d",shared->data[shared->datalength-1]);
sum += shared->data[shared->datalength-1];
printf("=%d\n",sum);
memset(shared, 0, sizeof(struct shm_data));
semaphore_v(semid);
} else {
semaphore_v(semid);
printf("no tasks, waiting.\n");
sleep(1);
}
}
}

e. 消费者与生成者结果图
消费者与生成者结果图

f. 共享内存原理
共享内存原理

g. 信号量的本质
信号量的本质