如何进程间通信?
1,fork后复制出的子进程都默认打开三个流,但都是虚拟的,文件描述符相同不一定是相同的文件(
文件描述符分别不同,0,1,2相同。3开始的可能相同;),不可取。
2,两个程序,产生两个进程。对于这两个进程可以操作同一个文件达到共享。
*********************************************************************************
进程间通信可以:
1,无名管道;
2,有名管道;
3,信号量;
4,信号
5,IPC对象,共享内核区
6,IPC对象,消息队列
7,信号灯
************************************************************************
1,无名管道:
pipe默认打开两个管道文件,一个0读1写;
fork产生子进程后,直接对无名管道进行操作。
-
#include <stdio.h>
-
#include <unistd.h>
-
#include <stdlib.h>
-
-
int main()
-
{
-
int fd[2];
-
-
if(-1 == pipe(fd))
-
{
-
perror("pipe");
-
exit(-1);
-
}
-
-
printf("%d %d\n", fd[0], fd[1]);//结果:3,4
-
-
pid_t pid = fork();
-
if(0 == pid)
-
{
-
close(fd[1]);//两个进程,一个进程只操作一个fd
-
sleep(3); //子进程读,父进程写
-
char buf[100] = {0};
-
read(fd[0], buf, 100);
-
printf("%s\n", buf);
-
}
-
else
-
if(0 < pid)
-
{
-
close(fd[0]);
-
write(fd[1], "hello", 5);
-
}
-
else
-
{
-
perror("fork");
-
exit(-1);
-
}
-
-
}
***************************************************************
2,有名管道:server.c产生写端:(两个程序前创建一个fifo管道文件)
-
#include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <stdlib.h>
-
-
int main(int argc, char **argv)
-
{
-
if(2 != argc)
-
{
-
printf("Usage: %s \n", argv[0]);
-
exit(-1);
-
}
-
-
int fd;
-
if(-1 == (fd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0666)))//管道文件操作同普通文件操作
-
{
-
perror("open");
-
exit(-1);
-
}
-
-
char buf[100];
-
while(1)
-
{
-
printf("input: ");fflush(stdout);
-
gets(buf);
-
write(fd, buf, 100);
-
}
-
-
}
client.c产生读端:
-
#include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <stdlib.h>
-
#include <strings.h>
-
-
int main(int argc, char **argv)
-
{
-
if(2 != argc)
-
{
-
printf("Usage: %s \n", argv[1]);
-
exit(-1);
-
}
-
-
int fd;
-
if(-1 == (fd = open(argv[1], O_RDONLY)))
-
{
-
perror("open");
-
exit(-1);
-
}
-
char buf[100] = {0};
-
while(1)
-
{
-
bzero(buf, 100);
-
read(fd, buf, 100);
-
-
if(0 == strncmp(buf, "time", 4))//如果是time quit则服务器端做出相应操作。
-
{
-
time_t t = time(NULL);
-
printf("recv :%s\n", ctime(&t));
-
-
}
-
else
-
if(0 == strncmp(buf, "quit", 4))
-
{
-
exit(0);
-
}
-
else
-
printf("recv :%s\n", buf);//其他直接打印
-
}
-
}
****************************************************************
3,信号量:类似线程信号量通信
hello.c
-
#include <stdio.h>
-
#include <fcntl.h> /* For O_* constants */
-
#include <sys/stat.h> /* For mode constants */
-
#include <semaphore.h>
-
#include <stdlib.h>
-
-
int main()
-
{
-
sem_t *a = sem_open("/mysem", O_CREAT, 0666, 1);
-
if(SEM_FAILED == a)
-
{
-
perror("sem_open");
-
exit(-1);
-
}
-
-
sem_t *b = sem_open("/mysem1", O_CREAT, 0666, 0);
-
if(SEM_FAILED == b)
-
{
-
perror("sem_open");
-
exit(-1);
-
}
-
-
while(1)
-
{
-
sem_wait(a);
-
sleep(1);
-
printf("hello\n");
-
sem_post(b);
-
}
-
}
world.c
点击(此处)折叠或打开
-
#include <stdio.h>
-
#include <fcntl.h> /* For O_* constants */
-
#include <sys/stat.h> /* For mode constants */
-
#include <semaphore.h>
-
#include <stdlib.h>
-
-
int main()
-
{
-
sem_t *a = sem_open("/mysem", O_CREAT, 0666, 1);
-
if(SEM_FAILED == a)
-
{
-
perror("sem_open");
-
exit(-1);
-
}
-
-
sem_t *b = sem_open("/mysem1", O_CREAT, 0666, 0);
-
if(SEM_FAILED == b)
-
{
-
perror("sem_open");
-
exit(-1);
-
}
-
-
while(1)
-
{
-
sem_wait(b);
-
sleep(1);
-
printf("world\n");
-
sem_post(a);
-
}
-
}
****************************************************************
4,信号通信:信号是软件层次上对中断机制的一种模拟,异步通信。
信号可以直接进行用户空间和内核空间之间进行交互,内核也可以通过它通知用户空间进程发生了哪些事。
如果该进程当前并未处于执行状态,则该信号就由内核保存起来,直到该进程恢复执行再传递给他;
----如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到取消阻塞才被传递给进程。
kill函数发送信号(-l,查看系统支持的信号列表);raise函数允许向自己发送信号。
如:signal(SIGUSR1, fun);signal函数是自定义收到信号的动作函数;这里定义本进程接收到SIGUSR1信号的动作(执行fun函数)。
kill(pid, SIGUSR2);kill函数用于发送信号;给pid号进程发信号SIGUSR2。
signal和kill函数配合使用。
信号可以打断任意的阻塞,被打断后的反应:
1,结束阻塞;
2,重启阻塞了的系统调用
如:int main(){
signal(sigusr1,fun);
sleep(10);//阻塞状态
printf();
}
未到10秒收到信号,则提前打印;即结束阻塞。
如:int main(){
signal(sigusr1,fun);
gets();//阻塞状态或者为其他阻塞函数如kill其他进程。
printf();
}
收到信号,则重启gets调用或再次调用kill。
alarm();可以在进程中设置一个定时器,指定时间到,内核就向进程发送SIGALARM信号
如:
void fun(int a)
{
printf("hello\n");
alarm(3);
}
int main()
{
signal(SIGALRM, fun);
alarm(3);
printf("alarm ....!\n");
while(1);
}可以完成循环打印hello。
pause();调用后挂起进程直到收到信号;可以节省CPU资源。
当外部发送11的信号给该进程后,该进程才会执行打印right。
-
#include <signal.h>
-
#include <stdio.h>
-
-
void fun(int a)
-
{
-
printf("right!\n");
-
exit(0);
-
}
-
-
-
int main()
-
{
-
signal(11, SIG_IGN);
-
-
printf("changed!\n");
-
-
while(1);//适当的方法是while(1)pause();使程序暂停。
-
}
******************************************************************
IPC对象-共享内存:
ipcs;查看所有共享内存的对象
ipcs -m;查看共享内存的对象-内存共享
ipcs -q;查看共享内存的对象-消息队列
5,对象-内存共享:
server.c
-
#include <stdio.h>
-
#include <sys/ipc.h>
-
#include <sys/shm.h>
-
#include <string.h>
-
#include <stdlib.h>
-
-
int main()
-
{
-
key_t key = ftok("/", 'a');/ftok和shmget组合使用
-
int shm_id = shmget(key, 100, IPC_CREAT|0666);//key为任意值,申请内存
-
if(-1 == shm_id)
-
{
-
perror("shmget");
-
exit(-1);
-
}
-
char *p = shmat(shm_id, NULL, 0666);//创建映射关系p和这段内存的关系
-
strcpy(p, "hello");
-
}
client.c
-
#include <stdio.h>
-
#include <sys/ipc.h>
-
#include <sys/shm.h>
-
#include <string.h>
-
#include <stdlib.h>
-
-
int main()
-
{
-
key_t key = ftok("/", 'a');
-
int shm_id = shmget(key, 100, 0666);//申请一块共同的内存
-
if(-1 == shm_id)
-
{
-
perror("shmget");
-
exit(-1);
-
}
-
char *p = shmat(shm_id, NULL, 0666);//映射关系,类型自定义
-
printf("%s\n", p);
-
shmdt(p);//删除映射关系
-
shmctl(shm_id, IPC_RMID, NULL);//释放内核内存区
-
-
}
**************************************************
6,IPC对象,消息队列
就是一个消息的列表,用户在列表中添加消息,读取消息。遵循队列的规则:先进先出,出后消息消失。
可以指定读取消息队列中为“ID”的消息(多次读该“ID”,则限定该ID消息读完为止)。(发消息时可以定各个消息的ID号)
server.c
-
#include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/ipc.h>
-
#include <sys/msg.h>
-
#define SIZE 100
-
typedef struct buf{
-
long type;
-
char msg[SIZE];
-
}BUF;
-
-
int main()
-
{
-
int msg_id = msgget(888, IPC_CREAT | 0666);//初始化消息队列
-
if(-1 == msg_id)//888:和队列相关的key值,用户指定,任意值|| IPC_CREAT | 0666:消息队列访问权限
-
{
-
perror("msgget");
-
exit(-1);
-
}
-
-
BUF buf = {1, "hello1"};
-
msgsnd(msg_id, &buf, SIZE, 0);//发送消息,msg_id队列号。||&buf特殊结构体type(即整形自定义“ID”)和自己的消息msg;。。;0表示发送完成才返回函数。
-
BUF buf1 = {1, "hello1"};
-
msgsnd(msg_id, &buf1, SIZE, 0);
-
BUF buf2 = {2, "hello2"};
-
msgsnd(msg_id, &buf2, SIZE, 0);
-
BUF buf3 = {1, "hello1"};
-
msgsnd(msg_id, &buf3, SIZE, 0);
-
BUF buf4 = {7, "hello7"};
-
msgsnd(msg_id, &buf4, SIZE, 0);
-
}
client.c //调用:./a.out ID
点击(此处)折叠或打开
-
#include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/ipc.h>
-
#include <sys/msg.h>
-
-
#define SIZE 100
-
typedef struct buf{
-
long type;
-
char msg[SIZE];
-
}BUF;
-
int main(int argc, char **argv)
-
{
-
if(2 != argc)
-
{
-
printf("Usage: %s \n", argv[0]);
-
exit(-1);
-
}
-
int msg_id = msgget(888, 0666);
-
if(-1 == msg_id)
-
{
-
perror("msgget");
-
exit(-1);
-
}
-
BUF buf;
-
msgrcv(msg_id, &buf, SIZE, atoi(argv[1]), 0);//接收消息函数:msg_id队列号;atoi(argv[1])前面提到的“ID”,0:无消息阻塞
-
printf("%s\n", buf.msg);
-
msgctl(msg_id, IPC_RMID, NULL);//IPC_RMID删除消息队列。
-
}
***********************************************************
7,信号灯:信号量集
也叫信号量,是对信号量的封装。
是不同进程和给定进程内部线程同步的机制。
一次性创建多个信号灯。
hello.c
-
#include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/ipc.h>
-
#include <sys/sem.h>
-
#include <stdlib.h>
-
void P(int sem_id, int num)
-
{
-
struct sembuf buf = {num, -1, 0};//特定结构体,信号灯编号,分配资源p操作、执行,0防死锁(死循环);
-
semop(sem_id, &buf, 1);1为要操作信号灯次数。
-
}
-
void V(int sem_id, int num)
-
{
-
struct sembuf buf = {num, 1, 0};//释放资源v操作,加1,防死锁
-
semop(sem_id, &buf, 1);
-
}
-
int main()
-
{
-
int sem_id = semget(888, 3,IPC_CREAT | 0666);//创建三个信号灯和信号灯关联的key 888; 访问权限。
-
if(-1 == sem_id)
-
{
-
perror("semget");
-
exit(-1);
-
}
-
semctl(sem_id, 0, SETVAL, 1);信号灯集编号,信号灯编号,SETVAL为设置信号灯值,值为1(同信号sem加1;减1)。
-
semctl(sem_id, 1, SETVAL, 0);
-
semctl(sem_id, 2, SETVAL, 0);
-
-
while(1)
-
{
-
P(sem_id, 0);
-
printf("hello\n");
-
V(sem_id, 1);
-
}
-
}
the.c
-
#include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/ipc.h>
-
#include <sys/sem.h>
-
#include <stdlib.h>
-
void P(int sem_id, int num)
-
{
-
struct sembuf buf = {num, -1, 0};
-
semop(sem_id, &buf, 1);
-
}
-
void V(int sem_id, int num)
-
{
-
struct sembuf buf = {num, 1, 0};
-
semop(sem_id, &buf, 1);
-
}
-
int main()
-
{
-
int sem_id = semget(888, 3, 0666);//每个进程都要执行的语句,这里不用creat
-
if(-1 == sem_id)
-
{
-
perror("semget");
-
exit(-1);
-
}
-
while(1)
-
{
-
P(sem_id, 1);
-
printf("the\n");
-
V(sem_id, 2);
-
}
-
}
world.c
-
#include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/ipc.h>
-
#include <sys/sem.h>
-
#include <stdlib.h>
-
void P(int sem_id, int num)
-
{
-
struct sembuf buf = {num, -1, 0};
-
semop(sem_id, &buf, 1);
-
}
-
void V(int sem_id, int num)
-
{
-
struct sembuf buf = {num, 1, 0};
-
semop(sem_id, &buf, 1);
-
}
-
int main()
-
{
-
int sem_id = semget(888, 3, 0666);
-
if(-1 == sem_id)
-
{
-
perror("semget");
-
exit(-1);
-
}
-
while(1)
-
{
-
P(sem_id, 2);
-
printf("world\n");
-
V(sem_id, 0);
-
}
-
}
******************************************
进程线程小结:
线程:
可重入性,线程安全函数
同步互斥,过程需要同步, 临界资源需要互斥
线程间通信
全局变量
信号量(无名信号量(内存):sem_t t;)
互斥锁
进程:
内存映射,
原始进程间通信方法
信号量(有名信号量sem_t *t = sem_open())
无名管道
有名管道
信号
IPC对象,共享内核区
IPC对象,消息队列
信号灯
阅读(4099) | 评论(0) | 转发(0) |