c语言多进程多线程编程(9)

2019-08-02 01:35

pipewrite(无名)管道特点:

?

read

管道是一个单向信道,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;

? ?

只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程); 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。

?

数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,且每次都是从缓冲区的头部读出数据。(先进先出)

Ex:

#include int pipe(int fileds[2]);

fileds[0] 用于读,fileds[1] 用于写。 读/写 —— 0/1

#include #include #include #include

int main() {

int pfds[2]; char buf[30]; pipe(pfds); if(fork()==0) {

close(pfds[0]); sleep(2);

write(pfds[1],\ exit(0); } else {

close(pfds[1]);

read(pfds[0],buf,30); wait(NULL); exit(0); } } note:

1.向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。

2. 写端对读端存在依赖性。只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIGPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则是应用程序终止)。

3.严格遵循先进先出(first in first out),不支持诸如lseek()等文件定位操作。

有名管道(named pipe或FIFO), 与管道不同之处在于,它与一个路径名关联,

以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信。

系统调用mkfifo ( ) 创建有名管道

int mkfifo(const char * pathname, mode_t mode)

该函数的第一个参数是一个普通的路径名,也就是创建后FIFO的名字。第二个参数与打开普通文件的open()函数中的mode 参数相同。如果mkfifo的第一个参数是一个已经存在的路径名时,会返回EEXIST错误,所以一般典型的调用代码首先会检查是否返回该错误,如果确实返回该错误,那么只要调用打开FIFO的函数就可以了。生成了有名管道后,就可以使用一般的文件I/O函数如

open、close、read、write等来对它进行操作。

Ex: 写:

#include #include #include #include

#define FIFO_SERVER \

main(int argc,char** argv) //参数为即将写入的字节数 {

int fd;

char w_buf[4096*2]; int real_wnum;

memset(w_buf,0,4096*2);

if((mkfifo(FIFO_SERVER,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST)) printf(\

if(fd==-1)

if(errno==ENXIO)

printf(\

//设置非阻塞标志

fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);

//设置阻塞标志 fd=open(FIFO_SERVER,O_WRONLY,0);

real_wnum=write(fd,w_buf,2048); if(real_wnum==-1) {

if(errno==EAGAIN)

printf(\ }

else

printf(\ }

读:

#include #include #include #include

#define FIFO_SERVER \

main(int argc,char** argv) {

char r_buf[4096*2]; int fd;

int r_size; int ret_size;

r_size=atoi(argv[1]);

printf(\ memset(r_buf,0,sizeof(r_buf));

fd=open(FIFO_SERVER,O_RDONLY|O_NONBLOCK,0); //fd=open(FIFO_SERVER,O_RDONLY,0);

//在此处可以把读程序编译成两个不同版本:阻塞版本及非阻塞版本

if(fd==-1) {

printf(\ exit(); }

while(1) {

memset(r_buf,0,sizeof(r_buf)); ret_size=read(fd,r_buf,r_size); if(ret_size==-1)

if(errno==EAGAIN)

printf(\

printf(\

sleep(1); }

pause();

unlink(FIFO_SERVER); } note:

管道是最古老的方式,具有通用性。但Pipe_buf有限,通常几百到几千字节。

4.3. 消息队列

系统 V IPC引入了三种进程间通信机制:消息、信号灯、共享内存。内核为每种机制维护一个表,在表中存储所有相关实例,每个表项由一个关键字(用户选择的名字)来标志。

将一个路径名和项目标识 转换为一个关键字: #include #include

key_t ftok(char* pathname,char proj);

Linux系统维护着一个msgque消息队列链表,其中每个元素指向一个描述消息队列的msqid_ds结构。当创建新的消息队列时,系统将从系统内存中分配一个msqid_ds结构,同时将其插入到数组中。

每个msqid_ds结构包含一个ipc_perm结构和指向已经进入此队列消息的指针,以及有关队列修改时间信息,如上次系统向队列中写入的时间等。 struct kern_ipc_perm {

key_t key; //该键值则唯一对应一个消息队列 uid_t uid; gid_t gid;

uid_t cuid; gid_t cgid; mode_t mode;

unsigned long seq; }

msqid_ds包含两个等待队列:一个为队列写入进程使用而另一个由队列读取进程使用。

每次进程试图向写入队列写入消息时,系统将把其有效用户和组标志符与此队列的ipc_perm结构中的模式进行比较。如果允许写入操作,则把此消息从此进程的地址空间拷贝到msg数据结构中,并放置到此消息队列尾部。由于 Linux严格限制可写入消息的个数和长度,队列中可能容纳不下这个消息。此时,此写入进程将被添加到这个消息队列的等待队列中,同时调用调度管理器选择新进程运行。当有消息从此队列中释放时,该进程将被唤醒。

从队列中读的过程与之类似。进程对这个写入队列的访问权限将被再次检验。读取进程将选择队列中第一个消息(不管是什么类型)或者第一个某特定类型的消息。如果没有消息可以满足此要求,读取进程将被添加 到消息队列的读取等待队列中,然后系统运行调度管理器。当有新消息写入队列时,进程将被唤


c语言多进程多线程编程(9).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:在公司薪酬改革动员会上的讲话

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: