当前位置:文档之家› Linux进程间通信和银行家算法

Linux进程间通信和银行家算法

Linux进程间通信和银行家算法
Linux进程间通信和银行家算法

Linux进程间通信——使用共享内存

下面将讲解进程间通信的另一种方式,使用共享内存。

一、什么是共享内存

顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样。而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。

特别提醒:共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取。所以我们通常需要用其他的机制来同步对共享内存的访问,例如前面说到的信号量。有关信号量的更多内容,可以查阅我的另一篇文章:Linux进程间通信——使用信号量

二、共享内存的使得

与信号量一样,在Linux中也提供了一组函数接口用于使用共享内存,而且使用共享共存的接口还与信号量的非常相似,而且比使用信号量的接口来得简单。它们声明在头文件 sys/shm.h中。

1、shmget函数

该函数用来创建共享内存,它的原型为:

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

第一个参数,与信号量的semget函数一样,程序需要提供一个参数key(非0整数),它有效地为共享内存段命名,shmget函数成功时返回一个与key相关的共享内存标识符(非负整数),用于后续的共享内存函数。调用失败返回-1.

不相关的进程可以通过该函数的返回值访问同一共享内存,它代表程序可能要使用的某个资源,程序对所有共享内存的访问都是间接的,程序先通过调用shmget 函数并提供一个键,再由系统生成一个相应的共享内存标识符(shmget函数的

返回值),只有shmget函数才直接使用信号量键,所有其他的信号量函数使用由semget函数返回的信号量标识符。

第二个参数,size以字节为单位指定需要共享的内存容量

第三个参数,shmflg是权限标志,它的作用与open函数的mode参数一样,如果要想在key标识的共享内存不存在时,创建它的话,可以与IPC_CREAT做或操作。共享内存的权限标志与文件的读写权限一样,举例来说,0644,它表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据,同时其他用户创建的进程只能读取共享内存。

2、shmat函数

第一次创建完共享内存时,它还不能被任何进程访问,shmat函数的作用就是用来启动对该共享内存的访问,并把共享内存连接到当前进程的地址空间。它的原型如下:

void *shmat(int shm_id, const void *shm_addr, int shmflg);

第一个参数,shm_id是由shmget函数返回的共享内存标识。

第二个参数,shm_addr指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。

第三个参数,shm_flg是一组标志位,通常为0。

调用成功时返回一个指向共享内存第一个字节的指针,如果调用失败返回-1.

3、shmdt函数

该函数用于将共享内存从当前进程中分离。注意,将共享内存分离并不是删除它,只是使该共享内存对当前进程不再可用。它的原型如下:

int shmdt(const void *shmaddr);

参数shmaddr是shmat函数返回的地址指针,调用成功时返回0,失败时返回-1.

4、shmctl函数

与信号量的semctl函数一样,用来控制共享内存,它的原型如下:

int shmctl(int shm_id, int command, struct shmid_ds *buf);

第一个参数,shm_id是shmget函数返回的共享内存标识符。

第二个参数,command是要采取的操作,它可以取下面的三个值:

IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。

IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值

IPC_RMID:删除共享内存段

第三个参数,buf是一个结构指针,它指向共享内存模式和访问权限的结构。shmid_ds结构至少包括以下成员:

struct shmid_ds

{

uid_t shm_perm.uid;

uid_t shm_perm.gid;

mode_t shm_perm.mode;

};

三、使用共享内存进行进程间通信

说了这么多,又到了实战的时候了。下面就以两个不相关的进程来说明进程间如何通过共享内存来进行通信。其中一个文件shmread.c创建共享内存,并读取其中的信息,另一个文件shmwrite.c向共享内存中写入数据。为了方便操作和数据结构的统一,为这两个文件定义了相同的数据结构,定义在文件shmdata.c 中。结构shared_use_st中的written作为一个可读或可写的标志,非0:表示可读,0表示可写,text则是内存中的文件。

shmdata.h的源代码如下:

#ifndef _SHMDATA_H_HEADER

#define _SHMDATA_H_HEADER

#define TEXT_SZ 2048

struct shared_use_st

{

int written;//作为一个标志,非0:表示可读,0表示可写

char text[TEXT_SZ];//记录写入和读取的文本

};

#endif

源文件shmread.c的源代码如下:

#include

#include

#include

#include

#include "shmdata.h"

int main()

{

int running = 1;//程序是否继续运行的标志

void *shm = NULL;//分配的共享内存的原始首地址

struct shared_use_st *shared;//指向shm

int shmid;//共享内存标识符

//创建共享内存

shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);

if(shmid == -1)

{

fprintf(stderr, "shmget failed\n");

exit(EXIT_FAILURE);

}

//将共享内存连接到当前进程的地址空间

shm = shmat(shmid, 0, 0);

if(shm == (void*)-1)

{

fprintf(stderr, "shmat failed\n");

exit(EXIT_FAILURE);

}

printf("\nMemory attached at %X\n", (int)shm);

//设置共享内存

shared = (struct shared_use_st*)shm;

shared->written = 0;

while(running)//读取共享内存中的数据

{

//没有进程向共享内存定数据有数据可读取

if(shared->written != 0)

{

printf("You wrote: %s", shared->text);

sleep(rand() % 3);

//读取完数据,设置written使共享内存段可写

shared->written = 0;

//输入了end,退出循环(程序)

if(strncmp(shared->text, "end", 3) == 0)

running = 0;

}

else//有其他进程在写数据,不能读取数据

sleep(1);

}

//把共享内存从当前进程中分离

if(shmdt(shm) == -1)

{

fprintf(stderr, "shmdt failed\n");

exit(EXIT_FAILURE);

}

//删除共享内存

if(shmctl(shmid, IPC_RMID, 0) == -1)

{

fprintf(stderr, "shmctl(IPC_RMID) failed\n");

exit(EXIT_FAILURE);

}

exit(EXIT_SUCCESS);

}

源文件shmwrite.c的源代码如下:

#include

#include

#include

#include

#include

#include "shmdata.h"

int main()

{

int running = 1;

void *shm = NULL;

struct shared_use_st *shared = NULL;

char buffer[BUFSIZ + 1];//用于保存输入的文本

int shmid;

//创建共享内存

shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);

if(shmid == -1)

{

fprintf(stderr, "shmget failed\n");

exit(EXIT_FAILURE);

}

//将共享内存连接到当前进程的地址空间

shm = shmat(shmid, (void*)0, 0);

if(shm == (void*)-1)

{

fprintf(stderr, "shmat failed\n");

exit(EXIT_FAILURE);

}

printf("Memory attached at %X\n", (int)shm);

//设置共享内存

shared = (struct shared_use_st*)shm;

while(running)//向共享内存中写数据

{

//数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本

while(shared->written == 1)

{

sleep(1);

printf("Waiting...\n");

}

//向共享内存中写入数据

printf("Enter some text: ");

fgets(buffer, BUFSIZ, stdin);

strncpy(shared->text, buffer, TEXT_SZ);

//写完数据,设置written使共享内存段可读

shared->written = 1;

//输入了end,退出循环(程序)

if(strncmp(buffer, "end", 3) == 0)

running = 0;

}

//把共享内存从当前进程中分离

if(shmdt(shm) == -1)

{

fprintf(stderr, "shmdt failed\n");

exit(EXIT_FAILURE);

}

sleep(2);

exit(EXIT_SUCCESS);

}

再来看看运行的结果:

分析:

1、程序shmread创建共享内存,然后将它连接到自己的地址空间。在共享内存的开始处使用了一个结构struct_use_st。该结构中有个标志written,当共享内存中有其他进程向它写入数据时,共享内存中的written被设置为0,程序等待。当它不为0时,表示没有进程对共享内存写入数据,程序就从共享内存中读取数据并输出,然后重置设置共享内存中的written为0,即让其可被shmwrite 进程写入数据。

2、程序shmwrite取得共享内存并连接到自己的地址空间中。检查共享内存中的written,是否为0,若不是,表示共享内存中的数据还没有被完,则等待其他进程读取完成,并提示用户等待。若共享内存的written为0,表示没有其他进程对共享内存进行读取,则提示用户输入文本,并再次设置共享内存中的written为1,表示写完成,其他进程可对共享内存进行读操作。

四、关于前面的例子的安全性讨论

这个程序是不安全的,当有多个程序同时向共享内存中读写数据时,问题就会出现。可能你会认为,可以改变一下written的使用方式,例如,只有当written 为0时进程才可以向共享内存写入数据,而当一个进程只有在written不为0

时才能对其进行读取,同时把written进行加1操作,读取完后进行减1操作。这就有点像文件锁中的读写锁的功能。咋看之下,它似乎能行得通。但是这都不是原子操作,所以这种做法是行不能的。试想当written为0时,如果有两个进程同时访问共享内存,它们就会发现written为0,于是两个进程都对其进行写操作,显然不行。当written为1时,有两个进程同时对共享内存进行读操作时也是如些,当这两个进程都读取完是,written就变成了-1.

要想让程序安全地执行,就要有一种进程同步的进制,保证在进入临界区的操作是原子操作。例如,可以使用前面所讲的信号量来进行进程的同步。因为信号量的操作都是原子性的。

五、使用共享内存的优缺点

1、优点:我们可以看到使用共享内存进行进程间的通信真的是非常方便,而且函数的接口也简单,数据的共享还使进程间的数据不用传送,而是直接访问内存,

也加快了程序的效率。同时,它也不像匿名管道那样要求通信的进程有一定的父子关系。

2、缺点:共享内存没有提供同步的机制,这使得我们在使用共享内存进行进程间通信时,往往要借助其他的手段来进行进程间的同步工作。

Linux进程间通信——使用消息队列

下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处。

一、什么是消息队列

消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制。

Linux用宏MSGMAX和MSGMNB来限制一条消息的最大长度和一个队列的最大长度。

二、在Linux中使用消息队列

Linux提供了一系列消息队列的函数接口来让我们方便地使用它来实现进程间

的通信。它的用法与其他两个System V PIC机制,即信号量和共享内存相似。

1、msgget函数

该函数用来创建和访问一个消息队列。它的原型为:

int msgget(key_t, key, int msgflg);

与其他的IPC机制一样,程序必须提供一个键来命名某个特定的消息队列。msgflg是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。msgflg可以与IPC_CREAT做或操作,表示当key所命名的消息队列不存在时创建一个消息队列,如果key所命名的消息队列存在时,IPC_CREAT标志会被忽略,而只返回一个标识符。

它返回一个以key命名的消息队列的标识符(非零整数),失败时返回-1.

2、msgsnd函数

该函数用来把消息添加到消息队列中。它的原型为:

int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg); msgid是由msgget函数返回的消息队列标识符。

msg_ptr是一个指向准备发送消息的指针,但是消息的数据结构却有一定的要求,指针msg_ptr所指向的消息结构一定要是以一个长整型成员变量开始的结构体,接收函数将用这个成员来确定消息的类型。所以消息结构要定义成这样:struct my_message{

long int message_type;

/* The data you wish to transfer*/

};

msg_sz是msg_ptr指向的消息的长度,注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括长整型消息类型成员变量的长度。

msgflg用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情。

如果调用成功,消息数据的一分副本将被放到消息队列中,并返回0,失败时返回-1.

3、msgrcv函数

该函数用来从一个消息队列获取消息,它的原型为

int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);

msgid, msg_ptr, msg_st的作用也函数msgsnd函数的一样。

msgtype可以实现一种简单的接收优先级。如果msgtype为0,就获取队列中的第一个消息。如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息。

msgflg用于控制当队列中没有相应类型的消息可以接收时将发生的事情。

调用成功时,该函数返回放到接收缓存区中的字节数,消息被复制到由msg_ptr 指向的用户分配的缓存区中,然后删除消息队列中的对应消息。失败时返回-1.

4、msgctl函数

该函数用来控制消息队列,它与共享内存的shmctl函数相似,它的原型为:

int msgctl(int msgid, int command, struct msgid_ds *buf);

command是将要采取的动作,它可以取3个值,

IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。

IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值

IPC_RMID:删除消息队列

buf是指向msgid_ds结构的指针,它指向消息队列模式和访问权限的结构。msgid_ds结构至少包括以下成员:

struct msgid_ds

{

uid_t shm_perm.uid;

uid_t shm_perm.gid;

mode_t shm_perm.mode;

};

成功时返回0,失败时返回-1.

三、使用消息队列进行进程间通信

马不停蹄,介绍完消息队列的定义和可使用的接口之后,我们来看看它是怎么让进程进行通信的。由于可以让不相关的进程进行行通信,所以我们在这里将会编写两个程序,msgreceive和msgsned来表示接收和发送信息。根据正常的情况,我们允许两个程序都可以创建消息,但只有接收者在接收完最后一个消息之后,它才把它删除。

接收信息的程序源文件为msgreceive.c的源代码为:

#include

#include

#include

#include

#include

#include

struct msg_st

{

long int msg_type;

char text[BUFSIZ];

};

int main()

{

int running = 1;

int msgid = -1;

struct msg_st data;

long int msgtype = 0; //注意1

//建立消息队列

msgid = msgget((key_t)1234, 0666 | IPC_CREAT);

if(msgid == -1)

{

fprintf(stderr, "msgget failed with error: %d\n", errno);

exit(EXIT_FAILURE);

}

//从队列中获取消息,直到遇到end消息为止

while(running)

{

if(msgrcv(msgid, (void*)&data, BUFSIZ, msgtype, 0) == -1)

{

fprintf(stderr, "msgrcv failed with errno: %d\n", errno);

exit(EXIT_FAILURE);

}

printf("You wrote: %s\n",data.text);

//遇到end结束

if(strncmp(data.text, "end", 3) == 0)

running = 0;

}

//删除消息队列

if(msgctl(msgid, IPC_RMID, 0) == -1)

{

fprintf(stderr, "msgctl(IPC_RMID) failed\n");

exit(EXIT_FAILURE);

}

exit(EXIT_SUCCESS);

}

发送信息的程序的源文件msgsend.c的源代码为:

#include

#include

#include

#include

#include

#include

#define MAX_TEXT 512

struct msg_st

{

long int msg_type;

char text[MAX_TEXT];

};

int main()

{

int running = 1;

struct msg_st data;

char buffer[BUFSIZ];

int msgid = -1;

//建立消息队列

msgid = msgget((key_t)1234, 0666 | IPC_CREAT);

if(msgid == -1)

{

fprintf(stderr, "msgget failed with error: %d\n", errno);

exit(EXIT_FAILURE);

}

//向消息队列中写消息,直到写入end

while(running)

{

//输入数据

printf("Enter some text: ");

fgets(buffer, BUFSIZ, stdin);

data.msg_type = 1; //注意2

strcpy(data.text, buffer);

//向队列发送数据

if(msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1)

{

fprintf(stderr, "msgsnd failed\n");

exit(EXIT_FAILURE);

}

//输入end结束输入

if(strncmp(buffer, "end", 3) == 0)

running = 0;

sleep(1);

}

exit(EXIT_SUCCESS);

}

运行结果如下:

四、例子分析——消息类型

这里主要说明一下消息类型是怎么一回事,注意msgreceive.c文件main函数中定义的变量msgtype(注释为注意1),它作为msgrcv函数的接收信息类型参数的值,其值为0,表示获取队列中第一个可用的消息。再来看看msgsend.c文件中while循环中的语句data.msg_type = 1(注释为注意2),它用来设置发送的信息的信息类型,即其发送的信息的类型为1。所以程序msgreceive能够接收到程序msgsend发送的信息。

如果把注意1,即msgreceive.c文件main函数中的语句由long int msgtype = 0;改变为long int msgtype = 2;会发生什么情况,msgreceive将不能接收到程序msgsend发送的信息。因为在调用msgrcv函数时,如果msgtype(第四个参数)大于零,则将只获取具有相同消息类型的第一个消息,修改后获取的消息类型为2,而msgsend发送的消息类型为1,所以不能被msgreceive程序接收。重新编译msgreceive.c文件并再次执行,其结果如下:

我们可以看到,msgreceive并没有接收到信息和输出,而且当msgsend输入end 结束后,msgreceive也没有结束,通过jobs命令我们可以看到它还在后台运行着。

五、消息队列与命名管道的比较

消息队列跟命名管道有不少的相同之处,通过与命名管道一样,消息队列进行通信的进程可以是不相关的进程,同时它们都是通过发送和接收的方式来传递数据的。在命名管道中,发送数据用write,接收数据用read,则在消息队列中,发送数据用msgsnd,接收数据用msgrcv。而且它们对每个数据都有一个最大长度的限制。

与命名管道相比,消息队列的优势在于,1、消息队列也可以独立于发送和接收进程而存在,从而消除了在同步命名管道的打开和关闭时可能产生的困难。2、同时通过发送消息还可以避免命名管道的同步和阻塞问题,不需要由进程自己来提供同步方法。3、接收程序可以通过消息类型有选择地接收数据,而不是像命名管道中那样,只能默认地接收。

银行家算法的C语言实现

Linux系统编程实验六进程间通信

实验六:进程间通信 实验目的: 学会进程间通信方式:无名管道,有名管道,信号,消息队列, 实验要求: (一)在父进程中创建一无名管道,并创建子进程来读该管道,父进程来写该管道(二)在进程中为SIGBUS注册处理函数,并向该进程发送SIGBUS信号(三)创建一消息队列,实现向队列中存放数据和读取数据 实验器材: 软件:安装了Linux的vmware虚拟机 硬件:PC机一台 实验步骤: (一)无名管道的使用 1、编写实验代码pipe_rw.c #include #include #include #include #include #include int main() { int pipe_fd[2];//管道返回读写文件描述符 pid_t pid; char buf_r[100]; char* p_wbuf; int r_num; memset(buf_r,0,sizeof(buf_r));//将buf_r初始化 char str1[]=”parent write1 “holle””; char str2[]=”parent write2 “pipe”\n”; r_num=30; /*创建管道*/ if(pipe(pipe_fd)<0) { printf("pipe create error\n"); return -1; } /*创建子进程*/ if((pid=fork())==0) //子进程执行代码 {

//1、子进程先关闭了管道的写端 close(pipe_fd[1]); //2、让父进程先运行,这样父进程先写子进程才有内容读sleep(2); //3、读取管道的读端,并输出数据 if(read(pipe_fd[0],buf_r, r_num)<0) { printf(“read error!”); exit(-1); } printf(“%s\n”,buf_r); //4、关闭管道的读端,并退出 close(pipe_fd[1]); } else if(pid>0) //父进程执行代码 { //1、父进程先关闭了管道的读端 close(pipe_fd[0]); //2、向管道写入字符串数据 p_wbuf=&str1; write(pipe_fd[1],p_wbuf,sizof(p_wbuf)); p_wbuf=&str2; write(pipe_fd[1],p_wbuf,sizof(p_wbuf)); //3、关闭写端,并等待子进程结束后退出 close(pipe_fd[1]); } return 0; } /*********************** #include #include #include #include #include #include int main() { int pipe_fd[2];//管道返回读写文件描述符 pid_t pid; char buf_r[100]; char* p_wbuf; int r_num;

Windows进程间各种通信方式浅谈

Windows进程间各种通信方式浅谈 1、Windows进程间通信的各种方法 进程是装入内存并准备执行的程序,每个进程都有私有的虚拟地址空间,由代码、数据以及它可利用的系统资源(如文件、管道等)组成。 多进程/多线程是Windows操作系统的一个基本特征。Microsoft Win32应用编程接口(Application Programming Interface, API) 提供了大量支持应用程序间数据共享和交换的机制,这些机制行使的活动称为进程间通信(InterProcess Communication, IPC),进程通信就是指不同进程间进行数据共享和数据交换。 正因为使用Win32 API进行进程通信方式有多种,如何选择恰当的通信方式就成为应用开发中的一个重要问题, 下面本文将对Win32中进程通信的几种方法加以分析和比较。 2、进程通信方法 2.1 文件映射 文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待。因此,进程不必使用文件I/O操作,只需简单的指针操作就可读取和修改文件的内容。 Win32 API允许多个进程访问同一文件映射对象,各个进程在它自己的地址空间里接收内存的指针。通过使用这些指针,不同进程就可以读或修改文件的内容,实现了对文件中数据的共享。 应用程序有三种方法来使多个进程共享一个文件映射对象。 (1)继承:第一个进程建立文件映射对象,它的子进程继承该对象的句柄。 (2)命名文件映射:第一个进程在建立文件映射对象时可以给该对象指定一个名字(可与文件名不同)。第二个进程可通过这个名字打开此文件映射对象。另外,第一个进程也可以通过一些其它IPC机制(有名管道、邮件槽等)把名字传给第二个进程。 (3)句柄复制:第一个进程建立文件映射对象,然后通过其它IPC机制(有名管道、

Linux进程间通信(2)实验报告

实验六:Linux进程间通信(2)(4课时) 实验目的: 理解进程通信原理;掌握进程中信号量、共享内存、消息队列相关的函数的使用。实验原理: Linux下进程通信相关函数除上次实验所用的几个还有: 信号量 信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是前一节的共享内存方式的进程间通信。要调用的第一个函数是semget,用以获得一个信号量ID。 int semget(key_t key, int nsems, int flag); key是IPC结构的关键字,flag将来决定是创建新的信号量集合,还是引用一个现有的信号量集合。nsems是该集合中的信号量数。如果是创建新集合(一般在服务器中),则必须指定nsems;如果是引用一个现有的信号量集合(一般在客户机中)则将nsems指定为0。 semctl函数用来对信号量进行操作。 int semctl(int semid, int semnum, int cmd, union semun arg); 不同的操作是通过cmd参数来实现的,在头文件sem.h中定义了7种不同的操作,实际编程时可以参照使用。 semop函数自动执行信号量集合上的操作数组。 int semop(int semid, struct sembuf semoparray[], size_t nops); semoparray是一个指针,它指向一个信号量操作数组。nops规定该数组中操作的数量。 ftok原型如下: key_t ftok( char * fname, int id ) fname就是指定的文件名(该文件必须是存在而且可以访问的),id是子序号,虽然为int,但是只有8个比特被使用(0-255)。 当成功执行的时候,一个key_t值将会被返回,否则-1 被返回。 共享内存 共享内存是运行在同一台机器上的进程间通信最快的方式,因为数据不需要在不同的进程间复制。通常由一个进程创建一块共享内存区,其余进程对这块内存区进行读写。首先要用的函数是shmget,它获得一个共享存储标识符。 #include #include #include int shmget(key_t key, int size, int flag); 当共享内存创建后,其余进程可以调用shmat()将其连接到自身的地址空间中。 void *shmat(int shmid, void *addr, int flag); shmid为shmget函数返回的共享存储标识符,addr和flag参数决定了以什么方式来确定连接的地址,函数的返回值即是该进程数据段所连接的实际地

进程间通信的四种方式

一、剪贴板 1、基础知识 剪贴板实际上是系统维护管理的一块内存区域,当在一个进程中复制数据时,是将这个数据放到该块内存区域中,当在另一个进程中粘贴数据时,是从该内存区域中取出数据。 2、函数说明: (1)、BOOL OpenClipboard( ) CWnd类的OpenClipboard函数用于打开剪贴板。若打开剪贴板成功,则返回非0值。若其他程序或当前窗口已经打开了剪贴板,则该函数返回0值,表示打开失败。若某个程序已经打开了剪贴板,则其他应用程序将不能修改剪贴板,直到前者调用了CloseClipboard函数。 (2)、BOOL EmptyClipboard(void) EmptyClipboard函数将清空剪贴板,并释放剪贴板中数据的句柄,然后将剪贴板的所有权分配给当前打开剪贴板的窗口。 (3)、HANDLE SetClipboardData(UINT uFormat, HANDLE hMem) SetClipboardData函数是以指定的剪贴板格式向剪贴板上放置数据。uFormat指定剪贴板格式,这个格式可以是已注册的格式,或是任一种标准的剪贴板格式。CF_TEXT表示文本格式,表示每行数据以回车换行(0x0a0x0d)终止,空字符作为数据的结尾。hMem指定具有指定格式的数据的句柄。hMem参数可以是NULL,指示采用延迟提交技术,则该程序必须处理WM_RENDERFORMA T和WM_RENDERALLFORMATS消息。应用程序在调用SetClipboardData函数之后,就拥有了hMem参数所标识的数据对象,该应用程序可以读取该数据对象,但在应用程序调用CloseClipboard函数之前,它不能释放该对象的句柄,或者锁定这个句柄。若hMem标识了一个内存对象,那么这个对象必须是利用GMEM_MOVEABLE标志调用GlobalAlloc函数为其分配内存。 注意:调用SetClipboardData函数的程序必须是剪贴板的拥有者,且在这之前已经打开了剪贴板。 延迟提交技术:当一个提供数据的进程创建了剪贴板数据之后,直到其他进程获取剪贴板数据之前,这些数据都要占据内存空间。若在剪贴板上放置的数据过大,就会浪费内存空间,降低对资源的利用率。为了避免这种浪费,就可以采用延迟提交计数,也就是由数据提供进程先提供一个指定格式的空剪贴板数据块,即把SetClipboardData函数的hMem参数设置为NULL。当需要获取数据的进程想要从剪贴板上得到数据时,操作系统会向数据提供进程发送WM_RENDERFORMA T消息,而数据提供进程可以响应这个消息,并在此消息的响应函数中,再一次调用SetClipboardData函数,将实际的数据放到剪贴板上。当再次调用SetClipboardData函数时,就不再需要调用OpenClipboard函数,也不再需要调用EmptyClipboard函数。也就是说,为了提高资源利用率,避免浪费内存空间,可以采用延迟提交技术。第一次调用SetClipboardData函数时,将其hMem参数设置为NULL,在剪贴板上以指定的剪贴板格式放置一个空剪贴板数据块。然后直到有其他进程需要数据或自身进程需要终止运行时再次调用SetClipboardData函数,这时才真正提交数据。 (4)、HGLOBAL GlobalAlloc( UINT uFlags,SIZE_T dwBytes); GlobalAlloc函数从堆上分配指定数目的字节。uFlags是一个标记,用来指定分配内存的方式,uFlags为0,则该标记就是默认的GMEM_FIXED。dwBytes指定分配的字节数。

Linux进程通信实验报告

Linux进程通信实验报告 一、实验目的和要求 1.进一步了解对进程控制的系统调用方法。 2.通过进程通信设计达到了解UNIX或Linux系统中进程通信的基本原理。 二、实验内容和原理 1.实验编程,编写程序实现进程的管道通信(设定程序名为pipe.c)。使 用系统调用pipe()建立一条管道线。而父进程从则从管道中读出来自 于两个子进程的信息,显示在屏幕上。要求父进程先接受子进程P1 发来的消息,然后再接受子进程P2发来的消息。 2.可选实验,编制一段程序,使其实现进程的软中断通信(设定程序名为 softint.c)。使用系统调用fork()创建两个子进程,再用系统调用 signal()让父进程捕捉键盘上来的中断信号(即按Del键),当父进程 接受这两个软中断的其中一个后,父进程用系统调用kill()向两个子 进程分别发送整数值为16和17的软中断信号,子进程获得对应软中 断信号后分别输出相应信息后终止。 三、实验环境 一台安装了Red Hat Linux 9操作系统的计算机。 四、实验操作方法和步骤 进入Linux操作系统,利用vi编辑器将程序源代码输入并保存好,然后 打开终端对程序进行编译运行。 五、实验中遇到的问题及解决 六、实验结果及分析 基本实验 可选实验

七、源代码 Pipe.c #include"stdio.h" #include"unistd.h" main(){ int i,j,fd[2]; char S[100]; pipe(fd); if(i=fork==0){ sprintf(S,"child process 1 is sending a message \n"); write(fd[1],S,50); sleep(3); return; } if(j=fork()==0){ sprintf(S,"child process 2 is sending a message \n"); write(fd[1],S,50); sleep(3); return;

进程间通信方式比较

进程间的通信方式: 1.管道(pipe)及有名管道(named pipe): 管道可用于具有亲缘关系进程间的通信,有名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。 2.信号(signal): 信号是在软件层次上对中断机制的一种模拟,它是比较复杂的通信方式,用于通知进程有某事件发生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一致得。 3.消息队列(message queue): 消息队列是消息的链接表,它克服了上两种通信方式中信号量有限的缺点,具有写权限得进程可以按照一定得规则向消息队列中添加新信息;对消息队列有读权限得进程则可以从消息队列中读取信息。 消息缓冲通信技术是由Hansen首先提出的,其基本思想是:根据”生产者-消费者”原理,利用内存中公用消息缓冲区实现进程之间的信息交换. 内存中开辟了若干消息缓冲区,用以存放消息.每当一个进程向另一个进程发送消息时,便申请一个消息缓冲区,并把已准备好的消息送到缓冲区,然后把该消息缓冲区插入到接收进程的消息队列中,最后通知接收进程.接收进程收到发送里程发来的通知后,从本进程的消息队列中摘下一消息缓冲区,取出所需的信息,然后把消息缓冲区不定期给系统.系统负责管理公用消息缓冲区以及消息的传递. 一个进程可以给若干个进程发送消息,反之,一个进程可以接收不同进程发来的消息.显然,进程中关于消息队列的操作是临界区.当发送进程正往接收进程的消息队列中添加一条消息时,接收进程不能同时从该消息队列中到出消息:反之也一样. 消息缓冲区通信机制包含以下列内容:

(1) 消息缓冲区,这是一个由以下几项组成的数据结构: 1、消息长度 2、消息正文 3、发送者 4、消息队列指针 (2)消息队列首指针m-q,一般保存在PCB中。 (1)互斥信号量m-mutex,初值为1,用于互斥访问消息队列,在PCB中设置。 (2)同步信号量m-syn,初值为0,用于消息计数,在PCB中设置。(3)发送消息原语send (4)接收消息原语receive(a) 4.共享内存(shared memory): 可以说这是最有用的进程间通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据得更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。 这种通信模式需要解决两个问题:第一个问题是怎样提供共享内存;第二个是公共内存的互斥关系则是程序开发人员的责任。 5.信号量(semaphore): 主要作为进程之间及同一种进程的不同线程之间得同步和互斥手段。 6.套接字(socket); 这是一种更为一般得进程间通信机制,它可用于网络中不同机器之间的进程间通信,应用非常广泛。 https://www.doczj.com/doc/4910156599.html,/eroswang/archive/2007/09/04/1772350.aspx linux下的进程间通信-详解

linux进程间通讯的几种方式的特点和优缺点

1. # 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。 # 有名管道(named pipe) :有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。 # 信号量( semophore ) :信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。 # 消息队列( message queue ) :消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 # 信号( sinal ) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。#共享内存( shared memory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。 # 套接字( socket ) :套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。 管道的主要局限性正体现在它的特点上: 只支持单向数据流; 只能用于具有亲缘关系的进程之间; 没有名字; 管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小);管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等; 2. 用于进程间通讯(IPC)的四种不同技术: 1. 消息传递(管道,FIFO,posix和system v消息队列) 2. 同步(互斥锁,条件变量,读写锁,文件和记录锁,Posix和System V信号灯) 3. 共享内存区(匿名共享内存区,有名Posix共享内存区,有名System V共享内存区) 4. 过程调用(Solaris门,Sun RPC) 消息队列和过程调用往往单独使用,也就是说它们通常提供了自己的同步机制.相反,共享内存区

进程间的通信

# 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。 # 有名管道(named pipe) :有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。 # 信号量( semophore ) :信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。 # 消息队列( message queue ) :消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 # 信号( sinal ) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。# 共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。 # 套接字( socket ) :套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。 windows进程通信的几种方式(转) 2008-10-13 16:47 1 文件映射 文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待。因此,进程不必使用文件I/O操作,只需简单的指针操作就可读取和修改文件的内容。 Win32 API允许多个进程访问同一文件映射对象,各个进程在它自己的地址空间里接收内存的指针。通过使用这些指针,不同进程就可以读或修改文件的内容,实现了对文件中数据的共享。 应用程序有三种方法来使多个进程共享一个文件映射对象。 (1)继承:第一个进程建立文件映射对象,它的子进程继承该对象的句柄。 (2)命名文件映射:第一个进程在建立文件映射对象时可以给该对象指定一个名字(可与文件名不同)。第二个进程可通过这个名字打开此文件映射对象。另外,第一个进程也可以通过一些其它IPC机制(有名管道、邮件槽等)把名字传给第二个进程。 (3)句柄复制:第一个进程建立文件映射对象,然后通过其它IPC机制(有名管道、邮件槽等)把对象句柄传递给第二个进程。第二个进程复制该句柄就取得对该文件映射对象的访问权限。 文件映射是在多个进程间共享数据的非常有效方法,有较好的安全性。但文件映射只能用于本地机器的进程之间,不能用于网络中,而开发者还必须控制进程间的同步。 2 共享内存 Win32 API中共享内存(Shared Memory)实际就是文件映射的一种特殊情况。进程在创建文件映射对象时用0xFFFFFFFF来代替文件句柄(HANDLE),就表示了对应的文件映射对象是从操作系统页面文件访问内存,其它进程打开该文件映射

Linux下的进程间通信-详解

Linux下的进程间通信-详解 详细的讲述进程间通信在这里绝对是不可能的事情,而且笔者很难有信心说自己对这一部分内容的认识达到了什么样的地步,所以在这一节的开头首先向大家推荐著 名作者Richard Stevens的著名作品:《Advanced Programming in the UNIX Environment》,它的中文译本《UNIX环境高级编程》已有机械工业出版社出版,原文精彩,译文同样地道,如果你的确对在Linux下编程有浓 厚的兴趣,那么赶紧将这本书摆到你的书桌上或计算机旁边来。说这么多实在是难抑心中的景仰之情,言归正传,在这一节里,我们将介绍进程间通信最最初步和最 最简单的一些知识和概念。 首先,进程间通信至少可以通过传送打开文件来实现,不同的进程通过一个或多个文件来传递信息,事实上,在很多应用系统里,都使用了这种方法。但一般说来, 进程间通信(IPC:InterProcess Communication)不包括这种似乎比较低级的通信方法。Unix系统中实现进程间通信的方法很多,而且不幸的是,极少方法能在所有的Unix系 统中进行移植(唯一一种是半双工的管道,这也是最原始的一种通信方式)。而Linux作为一种新兴的操作系统,几乎支持所有的Unix下常用的进程间通信 方法:管道、消息队列、共享内存、信号量、套接口等等。下面我们将逐一介绍。 2.3.1 管道 管道是进程间通信中最古老的方式,它包括无名管道和有名管道两种,前者用于父进程和子进程间的通信,后者用于运行于同一台机器上的任意两个进程间的通信。 无名管道由pipe()函数创建: #include int pipe(int filedis[2]); 参数filedis返回两个文件描述符:filedes[0]为读而打开,filedes[1]为写而打开。filedes[1]的输出是filedes[0]的输入。下面的例子示范了如何在父进程和子进程间实现通信。 #define INPUT 0 #define OUTPUT 1 void main() { int file_descriptors[2]; /*定义子进程号 */ pid_t pid; char buf[256]; int returned_count; /*创建无名管道*/ pipe(file_descriptors); /*创建子进程*/ if((pid = fork()) == -1) { printf("Error in fork\n"); exit(1); } /*执行子进程*/ if(pid == 0) { printf("in the spawned (child) process...\n"); /*子进程向父进程写数据,关闭管道的读端*/ close(file_descriptors[INPUT]); write(file_descriptors[OUTPUT], "test data", strlen("test data"));

04--Linux系统编程-进程间通信

IPC方法 Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。 在进程间完成数据传递需要借助操作系统提供特殊的方法,如:文件、管道、信号、共享内存、消息队列、套接字、命名管道等。随着计算机的蓬勃发展,一些方法由于自身设计缺陷被淘汰或者弃用。现今常用的进程间通信方式有: ①管道(使用最简单) ②信号(开销最小) ③共享映射区(无血缘关系) ④本地套接字(最稳定) 管道 管道的概念: 管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质: 1. 其本质是一个伪文件(实为内核缓冲区) 2.由两个文件描述符引用,一个表示读端,一个表示写端。 3. 规定数据从管道的写端流入管道,从读端流出。 管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。 管道的局限性: ①数据自己读不能自己写。 ②数据一旦被读走,便不在管道中存在,不可反复读取。 ③由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。 ④只能在有公共祖先的进程间使用管道。

常见的通信方式有,单工通信、半双工通信、全双工通信。 pipe函数 创建管道 int pipe(int pipefd[2]); 成功:0;失败:-1,设置errno 函数调用成功返回r/w两个文件描述符。无需open,但需手动close。规定:fd[0] →r;fd[1] →w,就像0对应标准输入,1对应标准输出一样。向管道文件读写数据其实是在读写内核缓冲区。 管道创建成功以后,创建该管道的进程(父进程)同时掌握着管道的读端和写端。如何实现父子进程间通信呢?通常可以采用如下步骤: 1.父进程调用pipe函数创建管道,得到两个文件描述符fd[0]、fd[1]指向管道的读端和写端。 2.父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管道。 3.父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出。由于管道是利用环形队列实现的,数据从写端流入管道,从读端流出,这样就实现了进程间通信。 练习:父子进程使用管道通信,父写入字符串,子进程读出并,打印到屏幕。【pipe.c】 思考:为甚么,程序中没有使用sleep函数,但依然能保证子进程运行时一定会读到数据呢? 管道的读写行为 使用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志): 1.如果所有指向管道写端的文件描述符都关闭了(管道写端引用计数为0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。

Linux进程间通信程序设计

计算机与信息技术学院设计性实验报告 一、实验目的 (1)理解进程概念; (2)理解并掌握多进程开发模式; (3)理解并掌握Linux平台进程间数据的传送方法。 二、总体设计 (1)实验内容:编写程序实现进程的管道通信。用系统调用pipe( )建立一管道,创建两个二个子进程P1和P2分别向管道各写一句话: Message from child P1! Message from child P2! 父进程从管道中读出二个来自子进程的信息并显示。 (2)设计原理: 所谓管道,是指能够连接一个写进程和一个读进程、并允许它们进行通信的一个共享文件,又称为pipe文件。由写进程从管道的写入端(句柄1)将数据写入管道,而读进程则从管道的读出端(句柄0)读出数据。 通过管道的信息流 三、实验步骤: #include

#include #include #include # include #define BUFSIZE 100 int pid1,pid2; int main() { int fd[2]; char buf_out [BUFSIZE], buf_in [BUFSIZE]; if (pipe(fd) < 0) { printf("pipe error\n"); exit(1); } /*创建一个管道*/ if ((pid1 = fork()) < 0) /*创建子进程1*/ { printf("fork1 failure\n"); exit(1); } else if (pid1 == 0) { lockf(fd[1],1,0); strcpy(buf_out," Message from child P1!"); /*把串放入数组buf_out中*/ write(fd[1],buf_out,BUFSIZE); /*向管道写长为BUFSIZE字节的串*/ sleep(5); /*自我阻塞5秒*/ lockf(fd[1],0,0); exit(0); } else { while((pid2=fork( ))==-1); /*创建子进程2*/ if(pid2==0) { lockf(fd[1],1,0); /*互斥*/ sprintf(buf_out,"Message from child %d!",getpid()); write(fd[1], buf_out,BUFSIZE); sleep(5); lockf(fd[1],0,0); exit(0); } else { wait(0); /*同步*/ read(fd[0], buf_in,BUFSIZE); /*从管道中读长为BUFSIZE字节的串*/ printf("%s\n", buf_in); wait(0); read(fd[0], buf_in,BUFSIZE); printf("%s\n", buf_in); exit(0); } }

进程间通信的几种方式

进程间通信的几种方式 2009-06-19 23:28 (1)管道(Pipe):管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信。 (2)命名管道(named pipe):命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建。 (3)信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。 (4)消息(Message)队列:消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺 (5)共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。 (6)内存映射(mapped memory):内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。 (7)信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。 (8)套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字

linux管道通信(C语言)

Linux环境中管道通信的实现 ?摘要Linux系统提供了丰富的进程通信手段,如信号、信号灯、管道、共享内存、消息队列等,能有效地完成多个进程间的信息共享和数据交换。本文主要设 计了Linux环境中的管道通信,并给出了利用该技术制作程序运行进程通信的实 例。 ?关键词管道;进程通信;IPC;Motif;进程条 1 引言 Linux系统提供了丰富的进程通信手段,如信号、信号灯、管道、共享内存、消息队列等,能有效地完成多个进程间的信息共享和数据交换。管道作为最早的进程间通信机制之一,可以在进程之间提供简单的数据交换和通信功能。 2 管道技术简介 2.1 管道的概念及特点 管道分为无名管道和有名管道两种。无名管道可用于具有亲缘关系进程间的通信,如父子进程、兄弟进程。有名管道克服了管道没有名字的限制,允许无亲缘关系进程间的通信。本文应用的是无名管道通信机制。 管道具有以下特点: (1)管道是半双工的,数据只能单向流动;需要相互通信时,就要建立两个管道。 (2)只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程,有名管道则突破了这一限制)。 (3)单独构成一种独立的文件系统,并且只存在于内存中。 (4)数据的读出和写入都是单向的:一个进程向管道中写的数据被管道另一端的进程读出。写入的数据每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。 2.2 管道的创建 #include int pipe(int fd[2]) 该函数是Linux的一个系统调用,其创建的管道两端处于一个进程中间。要用其实现父子进程之间的通信则需要在由pipe()创建管道后,再由系统调用fork创建一个新的子进程,然后通过管道在这两个进程间传送数据,实现进程间的通信(同样,不是父子关系和两个进程,只要两个进程中存在亲缘关系

实验三2_Linux进程间通信

实验三2_Linux进程间通信 实验三 Linux进程间通信 一、实验目的 熟悉Linux下进程间通信机制,能够使用系统提供的各种通信机制实现并发进程间的数据交换。 二、实验题目 分别使用Linux下的共享存储区、消息、管道等通信机制,编程实现并发进程之间的相互通信。 三、背景材料 (一)需要用到的系统调用 实验可能需要用到的主要系统调用和库函数在下面列出,详细的使用方法说明通过“man 2 系统调用名”或者“man 3 函数名”命令获取。 fork() 创建一个子进程,通过返回值区分是在父进程还是子进程中执行; wait() 等待子进程执行完成; getpid() 获取当前进程id; shmget() 建立一个共享存储区; shmctl() 操纵一个共享存储区; shmat() 把一个共享存储区附接到进程内存空间; shmdt() 把一个已经附接的共享存储区从进程内存空间断开; msgget() 建立一个消息队列; msgctl() 操纵一个消息队列; msgsnd() 发送消息; msgrcv() 接收消息;

signal() 设置对信号的处理方式或处理过程; pipe() 打开管道; lockf() 锁定一个文件。 (二)使用共享存储区的示例程序 下面程序主要用来演示共享存储区的使用方法:首先要使用shmget得到共享存储区句柄(可以新建或连接已有的共享存储区,以关键字标识),然后使用shmat挂接到进程的存储空间(这样才能够访问),当使用完后,使用shmctl释放(shmctl 还可以完成一些其他功能)。这种使用逻辑也适用于消息和信号量。示例程序代码如下: #include #include #include #include #include int main(void) { int x, shmid; int *shmptr; if((shmid=shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT|0666)) < 0) printf("shmget error"), exit(1); //函数原型int shmget(key_t key,int size,int shmflg); 函数用于创建(或者获取)一 key键值指定的共享内存对象,返回该对象的系统标识符:shmid;size 是创个由

进程间通讯

全国嵌入式人才培训基地
4. 进程间通信 上一页 第 30 章 进程 下一页
4. 进程间通信
请点评
每个进程各自有不同的用户地址空间, 任何一个进程的全局变量在另一个进程中 都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区, 进程 2 再从内核缓冲区把数据读走, 进程 1 把数据从用户空间拷到内核缓冲区, 内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。 如下图所示。 图 30.6. 进程间通信
4.1. 管道 请点评
管道是一种最基本的 IPC 机制,由 pipe 函数创建:
#include
int pipe(int filedes[2]);
调用 pipe 函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读 端一个写端, 然后通过 filedes 参数传出给用户程序两个文件描述符, filedes[0] 指向管道的读端,filedes[1]指向管道的写端(很好记,就像 0 是标准输入 1 是标准输出一样)。所以管道在用户程序看起来就像一个打开的文件,通过 read(filedes[0]);或者 write(filedes[1]);向这个文件读写数据其实是在读 写内核缓冲区。pipe 函数调用成功返回 0,调用失败返回-1。

开辟了管道之后如何实现两个进程间的通信呢?比如可以按下面的步骤通信。 图 30.7. 管道
得到两个文件描述符指向管道的两端。 1. 父进程调用 pipe 开辟管道, 2. 父进程调用 fork 创建子进程,那么子进程也有两个文件描述符指 向同一管道。 3. 父进程关闭管道读端,子进程关闭管道写端。父进程可以往管道里 写,子进程可以从管道里读,管道是用环形队列实现的,数据从写 端流入从读端流出,这样就实现了进程间通信。 例 30.7. 管道

操作系统课程设计:Linux系统管理实践与进程通信实现

操作系统课程设计:Linux系统管理实践与进程通信实现

操作系统课程设计——Linux系统管理实践与进程通信实现 班级网络10 学号 31006100 姓名 YHD 指导老师詹永照

二零一三年一月八号 一、设计内容 1、Linux系统的熟悉与常用操作命令的掌握。 2、Linux环境下进程通信的实现。(实现父母子女放水果吃水果的同步互斥问题,爸爸放苹果,女儿专等吃苹果,妈妈放橘子,儿子专等吃橘子,盘子即为缓冲区,大小为5。) 二、Linux环境介绍 1、Linux的由来与发展 Linux是一种可以在PC机上执行的类似UNIX的操作系统,是一个完全免费的操作系统。1991年,芬兰学生Linux Torvalds开发了这个操作系统的核心部分,因为是Linux改良的minix系统,故称之为Linux。 2、Linux的优点 (1)Linux具备UNIX系统的全部优点 Linux是一套PC版的UNIX系统,相对于Windows是一个十分稳定的系统,安全性好。 (2)良好的网络环境 Linux与UNIX一样,是以网络环境为基础的操作系统,具备完整的网络功能,提供在Internet或Intranet的邮件,FTP,www等各种服务。 (3)免费的资源 Linux免费的资源和公开的源代码方便了对操作系统的深入了解,给编程爱好者提供更大的发挥空间。 3、Linux的特点 1)全面的多任务,多用户和真正的32位操作系统 2)支持多种硬件,多种硬件平台

3)对应用程序使用的内存进行保护 4)按需取盘 5)共享内存页面 6)使用分页技术的虚拟内存 7)优秀的磁盘缓冲调度功能 8)动态链接共享库 9)支持伪终端设备 10)支持多个虚拟控制台 11)支持多种CPU 12)支持数字协处理器387的软件模拟 13)支持多种文件系统 14)支持POSIX的任务控制 15)软件移植性好 16)与其它UNIX系统的兼容性 17)强大的网络功能 三、常用命令介绍 1、目录操作 和DOS相似,Linux采用树型目录管理结构,由根目录(/)开始一层层将 子目录建下去,各子目录以 / 隔开。用户login后,工作目录的位置称为 home directory,由系统管理员设定。‘~’符号代表自己的home directory,例 如 ~/myfile 是指自己home目录下myfile这个文件。 Linux的通配符有三种:’*’和’?’用法与DOS相同,‘-‘代表区间内 的任一字符,如test[0-5]即代表test0,test1,……,test5的集合。 (1)显示目录文件 ls 执行格式: ls [-atFlgR] [name] (name可为文件或目录名称) 例: ls 显示出当前目录下的文件 ls -a 显示出包含隐藏文件的所有文件 ls -t 按照文件最后修改时间显示文件 ls -F 显示出当前目录下的文件及其类型

linux进程间通讯的几种方式

1.信号:(signal)是一种处理异步事件的方式。信号时比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程外,还可以发送信号给进程本身。 2.信号量:(Semaphore)进程间通信处理同步互斥的机制。是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。 linux进程间通讯的几种方式的特点和优缺点,和适用场合 1. 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。 有名管道(named pipe) :有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。 信号量( semophore ) :信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。消息队列( message queue ) :消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 信号( sinal ) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。 共享内存( shared memory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。

相关主题
文本预览
相关文档 最新文档