本文转自:http://blog.chinaunix.net/uid-25324849-id-207468.html
(9)进程间通信
注:所以文章红色字体代表需要特别注意和有问题还未解决的地方,蓝色字体表示需要注意的地方
1. 本文所介绍的程序平台
开发板:arm9-mini2440
虚拟机为:Red Hat Enterprise Linux 5
开发板上系统内核版本:linux-2.6.32.2
2. unix系统主要进程间通信机制(IPC)
管道
FIFO(命名管道)
消息队列
共享内存
信号量
套接字
3. 管道
详细请见:
http://blog.chinaunix.net/space.php?uid=25324849&do=blog&id=207407
管道是最常见的IPC机制,是单工的,如果要两个进程实现双向传输则需要两个管道,管道创建的时候既有两端,一个读端和一个写端。两个进程要协调好,一个进程从读的方向读,一个进程从写的方向写,并且只能在关系进程间进行,比如父子进程,通过系统调用pipe()函数实现。
#include <unistd.h>
int pipe(int fd[2]);
fd[0]:文件描述符,用于读操作
fd[1]:文件描述符,用于写操作
返回值:成功返回0,如果创建失败将返回-1并记录错误码
4. FIFO
详细请见:
http://blog.chinaunix.net/space.php?uid=25324849&do=blog&id=207413
FIFO又称命名管道,通过FIFO的通信可以发生在任何两个进程之间,且只需要对FIFO有适当的访问权限,对FIFO的读写操作与普通文件类似,命名管道的创建是通过mkfifo()函数创建的。
#include <sys/type.h>
int mkfifo(const char *filename, mode_t mode)
filename:命名管道的文件名
mode:访问权限
返回值:若成功则返回0,否则返回-1,错误原因存于errno中。
4.1 FIFO服务器实例
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#define SERVER_FIFO_NAME "./serv_fifo"
#define CLIENT_FIFO_NAME "./cli_%d_fifo"
#define BUFFER_SIZE 20
struct data_to_pass_st {
pid_t client_pid;
char some_data[BUFFER_SIZE - 1];
};
int main()
{
int server_fifo_fd, client_fifo_fd;
struct data_to_pass_st my_data;
int read_res;
char client_fifo[256];
char *tmp_char_ptr;
mkfifo(SERVER_FIFO_NAME, 0777);
server_fifo_fd = open(SERVER_FIFO_NAME, O_RDONLY);
if (server_fifo_fd == -1) {
fprintf(stderr, "Server fifo failure\n");
exit(EXIT_FAILURE);
}
sleep(10); /* lets clients queue for demo purposes */
do {
read_res = read(server_fifo_fd, &my_data, sizeof(my_data));
if (read_res > 0) {
tmp_char_ptr = my_data.some_data;
while (*tmp_char_ptr) {
*tmp_char_ptr = toupper(*tmp_char_ptr);
tmp_char_ptr++;
}
sprintf(client_fifo, CLIENT_FIFO_NAME, my_data.client_pid);
client_fifo_fd = open(client_fifo, O_WRONLY);
if (client_fifo_fd != -1) {
write(client_fifo_fd, &my_data, sizeof(my_data));
close(client_fifo_fd);
}
}
} while (read_res > 0);
close(server_fifo_fd);
unlink(SERVER_FIFO_NAME);
exit(EXIT_SUCCESS);
}
4.2 FIFO客户实例
#include <ctype.h> #include <ctype.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include <limits.h> #include <sys/types.h> #include <sys/stat.h> #define SERVER_FIFO_NAME "./serv_fifo" #define CLIENT_FIFO_NAME "./cli_%d_fifo" #define BUFFER_SIZE 20 struct data_to_pass_st { pid_t client_pid; char some_data[BUFFER_SIZE - 1]; }; int main() { int server_fifo_fd, client_fifo_fd; struct data_to_pass_st my_data; int times_to_send; char client_fifo[256]; server_fifo_fd = open(SERVER_FIFO_NAME, O_WRONLY); if (server_fifo_fd == -1) { fprintf(stderr, "Sorry, no server\n"); exit(EXIT_FAILURE); } my_data.client_pid = getpid(); sprintf(client_fifo, CLIENT_FIFO_NAME, my_data.client_pid); if (mkfifo(client_fifo, 0777) == -1) { fprintf(stderr, "Sorry, can't make %s\n", client_fifo); exit(EXIT_FAILURE); } for (times_to_send = 0; times_to_send < 5; times_to_send++) { sprintf(my_data.some_data, "Hello from %d", my_data.client_pid); printf("%d sent %s, ", my_data.client_pid, my_data.some_data); write(server_fifo_fd, &my_data, sizeof(my_data)); client_fifo_fd = open(client_fifo, O_RDONLY); if (client_fifo_fd != -1) { if (read(client_fifo_fd, &my_data, sizeof(my_data)) > 0) { printf("received: %s\n", my_data.some_data); } close(client_fifo_fd); } } close(server_fifo_fd); unlink(client_fifo); exit(EXIT_SUCCESS); }
5. 消息队列
详细请见:
http://blog.chinaunix.net/space.php?uid=25324849&do=blog&id=207459
消息队列有如下特点:
(1) 通过消息队列key值来定义和生成消息队列
(2) 任何进程只要有访问权限并且知道key就可以访问消息队列
(3) 消息队列为内存块方式数据段
(4) 消息队列的消息长度可为系统参数限制内的任何长度
(5) 消息队列有消息类型,访问可以按类型访问
(6) 在一次读写操作前都必须取得消息标识符,即访问权,访问后脱离关系
(7) 消息队列中的某条消息被读后立即自动的从消息队列中删除
(8) 消息队列具有加锁处理机制
(9) 在权限允许时,消息队列的信息可以双向传递
6. 共享内存
详细请见:
http://blog.chinaunix.net/space.php?uid=25324849&do=blog&id=207467
共享内存是效率最高的IPC机制,他允许任何两个进程访问相同的逻辑内存区,它具有一下特点:
(1) 通过共享内存key值定义和生成共享内存
(2) 任何进程只要有访问权限并且知道key就可以访问共享内存
(3) 共享内存为内存块方式数据段
(4) 共享内存的消息长度可为系统参数限制内的任何长度
(5) 共享内存的访问方式与数组的访问方式相同
(6) 在取得共享内存标识符将共享内存与进程数据段连接后即可以开始对其进行读写操作,在所有操作完成之后再做共享内存与进程数据段的脱离操作,才完成内存访问的过程
(7) 共享内存中的数据不会因为数据被进程读取后消失
(8) 共享内存不具备锁机制,所有共享内存最好与信号量一起使用来保证数据的一致性
(9) 在权限允许时,共享内存的信息传递时双向的
7. 信号量
详细请见:
http://blog.chinaunix.net/space.php?uid=25324849&do=blog&id=207464
信号量是一种同步机制,主要用途是保护临界资源(在一个时刻只能被一个进程所拥有),通常与共享内存一起使用。
6.1 semget()函数
#include <sys/sem.h>
int semget(key_t key, int num_sems, int sem_flags)
key:信号量集合的键
num_sems:信号量集合里面元素个数
sem_flags:任选参数
返回值:返回信号量集合标识符,出错返回-1
6.2 semop()函数
#include <sys/sem.h>
int semop(int sem_id, struct sembuf *sem_ops , size_t num_sem_ops)
sem_id: 信号量集合标识符
sem_ops:信号量操作结构的指针
num_sem_ops:信号量操作结构的个数
6.3 semctl)函数
#include <sys/sem.h>
int semctl (int sem_id, int sem_num, int command, …)
sem_id: 信号量集合标识符
sem_num:信号量元素编号
command:控制命令
…:命令参数列表
返回值:根据命令返回相应的值,出错返回-1