管道通信相关资料 linux系统调用

实验参考:LINUX系统调用

1. 进程控制的系统调用

l fork系统调用创建新的子进程

格式: pid=int fork()

fork调用返回时,系统中已有两个用户级环境完全相同的进程存在,这两个

进程从fork调用中得到的返回值不同,其中子进程得到的返回值为零,父进程

得到的返回值是新创建子进程的进程标识号。

l exec系统调用

格式:(六种)

int execl(path,arg0,arg1,…,argn,(char *)0)

char *path, *arg0, *arg1, …, *argn ;

exec调用进程的正文段被指定的目标文件的正文段所覆盖,其属性的变化方

式与fork成功后从父进程那里继承属性的方式几乎是一样的。系统中绝大多数

命令都是通过exec来执行的,不但shell进程所创建的子进程使用它来执行用户

命令,shell进程本身和它的祖先进程也是用exec来启动执行的。

l exit 系统调用终止进程执行

格式:void exit(status)

int status ;

参数status是调用进程终止时传递给其父进程的值。如调用进程还有子进

程,则将其所有子进程的父进程改为1号进程。

l wait 系统调用等待子进程暂仃或终止

格式:int wait(stat_loc) int wait((int *)0)

int stat_loc ;

wait 调用将调用进程挂起,直到该进程收到一个被其捕获的信号或者它的任

何一个子进程暂仃或终止为止。如果wait 调用之前已有子进程暂仃或终止,则

该调用立即返回。

l lockf 锁定文件

格式:int lockf(fd,fuction,size)

int files, fuction; long size; fd – 锁定文件标识

function=0不锁定表示

=1锁定

=2测试和锁定

=3测试有否被锁定

size --锁定或解锁的字节数,0表示从文件的当前位置到文件尾。

 

程序实例:

#include <stdio.h>

void main(intargc, char *argv[ ])

{ int pid;

pid=fork(); /*fork child process */

if (pid<0){fprintf(stderr, “Fork Failed”); exit(-1);

}

else if (pid==0){ execlp(“/bin/ls”,”ls”,NULL);

} /* childprocess */

else {wait(NULL);

printf(“child Complete”);

exit(0);

} /*parentprocess */

}

2.进程通信的管道方式

l  pipe系统调用

格式: intpipe (filedes)

int filedes [2];

 

程序实例:管道通信

#include <stdio.h>

#include <fcntl.h>

char parent[]={“A message from parent .”};

char child[]={“A message from child .”};

main()

{int chan1[2],chan2[2];

char buf[100];

if (pipe(chan1)==-1 || pipe(chan2)==-1) errexit(“pipe”);

if (fork())

{close(chan1[0]); close(chan2[1]);

write(chan1[1],parent,sizeof parent);

close(chan1[1]);

read(chan2[0],buf,100);

printf(“parent process : %s \n”,buf);

close(chan2[0]);

}

else

{close(chan1[1]); close(chan2[0]);

read(chan1[0],buf,100);

printf(“child process : %s \n”,buf);

write(chan2[1],child,sizeof child);

close(chan2[1]); close(chan1[0]);

}

}

 

3.进程通信的消息队列方式

 

消息队列就是消息的一个链表,它允许一个或多个进程向它写消息,一个或多个进程从中读消息。具有一定的FIFO的特性,但是可实现消息的随即查询。这些消息存在于内核中,由“队列ID”来标识。

消息队列的实现包括创建和打开队列、添加消息、读取消息和控制消息队列这四种操作。

msgget:创建和打开队列,其消息数量受系统限制。

msgsnd:添加消息,将消息添加到消息队列尾部。

msgrcv:读取消息,从消息队列中取走消息。

msgctl:控制消息队列。

int msgget (key_tkey, int flag) 

   key:返回新的或已有队列的ID,IPC_PRIVATE

int msgsnd (intmsqid, struct msgbuf  *msgp, size_t msgsz, int flag)

  其中:msqid是消息队列的队列ID;msgp是消息内容所在的缓冲区;msgsz是消息的大小;msgflg是标志,IPC_NOWAIT若消息并没有立即发送而调用进程会立即返回。

int msgrcv (intmsqid, struct  msgbuf *msgp, size_t msgsz,long  msgtyp, int flag)

msqid是消息队列的引用标识符;msgp是接收到的消息将要存放的缓冲区;msgsz是消息的大小;msgtyp是期望接收的消息类型;

int msgctl (intmsqid, int cmd, struct msqid_ds *buf)

 msqid是消息队列的引用标识符;cmd是执行命令;buf是一个缓冲区。cmd参数指定对于由msqid规定的队列要执行的命令:IPC_STAT 取此队列的msqid_ds结构,并将其存放在buf指向的结构中。IPC_SET 按由buf指向的结构中的值,设置与此队列相关的结构中的下列四个字段:msg_perm.uid、msg_perm.gid、msg_perm;mode和msg_qbytes。此命令只能由下列两种进程执行:一种是其有效用户ID等于msg_perm.cuid或msg_perm.uid;另一种是具有超级用户特权的进程。只有超级用户才能增加msg_qbytes的值。

IPC_RMID 从系统中删除该消息队列以及仍在该队列上的所有数据。这种删除立即生效。仍在使用这一消息队列的其他进程在它们下一次试图对此队列进行操作时,将出错返回 EIDRM。

此命令只能由下列两种进程执行:一种是其有效用户ID等于msg_perm.cuid或msg_perm.uid;另一种是具有超级用户特权的进程。msgflg是标志。

 

程序实例:

1)mesg_que_send.c

intmain()

{   

key_tkey;

intmsgkey;

pid_tpid;

intcount=0;

structmsgbuf{

       int mtype;

       pid_t from;

       int count;

       char mtext[50];

    }wmsg;

 key=ftok("/home/yandongsheng/",10);

 pid=getpid();//获得发送进程的id

 if((msgkey=msgget(key,IPC_CREAT|0660))<0)

     {

            fprintf(stderr,"msgget error%s\n",strerror(errno));

            exit(1);

        }

 printf("msgget key %d\n",msgkey);

fflush(stdout);

 while(1)

 {

   count++;

   bzero(&wmsg,sizeof(wmsg));

   wmsg.mtype=10; //消息的类型

    wmsg.count=count;

    wmsg.from=pid;

    strcpy(wmsg.mtext,"hello,i amcoming");

    if(msgsnd(msgkey,&wmsg,sizeof(wmsg.mtext),MSG_NOERROR)<0)

     {

            fprintf(stderr,"msgsnd error%s\n",strerror(errno));

        }

      sleep(2);

     }

     if((msgctl(msgkey,IPC_RMID,NULL))<0){

          perror("msgctl");

    exit(1);

    }

return0;

}

   

 

2)mesg_que_recv.c

 

intmain()

{   

    key_t key;

    pid_t pid;

    int msgkey;

    struct msgbuf{

       int mtype;

       pid_t from;

       int count;

       char mtext[50];

    }rmsg;//消息的格式应该是一样的

    pid=getpid();

   key=ftok("/home/yandongsheng/",10);

    while(1)

    {     

      bzero(&rmsg,sizeof(rmsg));

     if(msgrcv(msgkey,&rmsg,sizeof(rmsg.mtext),0,MSG_NOERROR)<0)

       {

        perror("msgrcv error");

       }

       printf("rmsg.from=%d\nmy pidis:",rmsg.from,pid);

       printf("rmsg.mtype=%d\nrmsg.count=%d\nrmsg.mtext=%s\n",rmsg.mtype,rmsg.count,rmsg.mtext);

      sleep(2);

    }

    if((msgctl(msgkey,IPC_RMID,NULL))<0){

          perror("msgctl");

    exit(1);

    }

return0;

}

 

 

先运行mesg_que_send.c 后运行mesg_que_recv.c 仅做演示

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 实验目的 1) 加深对进程概念的理解,明确进程和程序的区别。 2) 进一步认识并发执行的实质。 3) 分析进程争用资源的现象,学习解决进程互斥的方法。 4) 学习解决进程同步的方法。 5) 了解Linux系统中进程通信的基本原理。   进程是操作系统中最重要的概念,贯穿始终,也是学习现代操作系统的关键。通过本次实验,要求理解进程的实质和进程管理的机制。在Linux系统下实现进程从创建到终止的全过程,从中体会进程的创建过程、父进程和子进程之间的关系、进程状态的变化、进程之间的互斥、同步机制、进程调度的原理和以管道为代表的进程间的通信方式的实现。 2. 内容及要求:   这是一个设计型实验,要求自行编制程序。   使用系统调用pipe()建立一条管道,两个子进程分别向管道写一句话:   Child process1 is sending a message!   Child process2 is sending a message!   父进程从管道读出来自两个子进程的信息,显示在屏幕上。   要求: 1) 父进程先接收子进程1发来的消息,然后再接收子进程2发来的消息。 2) 实现管道的互斥使用,当一个子进程正在对管道进行写操作时,另一子进程必须等待。使用系统调用lockf(fd[1],1,0)实现对管道的加锁操作,用lockf(fd[1],0,0)解除对管道的锁定。 3) 实现父子进程的同步,当子进程把数据写入管道后,便去睡眠等待;当父进程试图从一空管道中读取数据时,也应等待,直到子进程将数据写入管道后,才将其唤醒。 3.相关系统调用 1) fork() 用于创一个子进程。 格式:int fork(); 返回值:在子进程中返回0;在父进程中返回所创建的子进程的ID值;当返回-1时,创建失败。 2) wait() 常用来控制父进程与子进程的同步。 在父进程中调用wait(),则父进程被阻塞,进入等待队列,等待子进程结束。当子进程结束时,父进程从wait()返回继续执行原来的程序。 返回值:大于0时,为子进程的ID值;等于-1时,调用失败。 3) exit() 是进程结束时最常调用的。 格式:void exit( int status); 其中,status为进程结束状态。 4) pipe() 用于创建一个管道 格式:pipe(int fd); 其中fd是一个由两个数组元素fd[0]和fd[1]组成的整型数组,fd[0]是管道的读端口,用于从管道读出数据,fd[1] 是管道的写端口,用于向管道写入数据。 返回值:0 调用成功;-1 调用失败。 5) sleep() 调用进程睡眠若干时间,之后唤醒。 格式:sleep(int t); 其中t为睡眠时间。 6) lockf() 用于对互斥资源加锁和解锁。在本实验中,该调用的格式为: lockf(fd[1],1,0);/* 表示对管道的写入端口加锁。 lockf(fd[1],0,0);/* 表示对管道的写入端口解锁。 7) write(fd[1],String,Length) 将字符串String的内容写入管道的写入口。 8) read(fd[0],String,Length) 从管道的读入口读出信息放入字符串String中。 4.程序流程 父进程: 1) 创建管道; 2) 创建子进程1; 3) 创建子进程2; 4) 等待从管道中读出子进程1写入的数据,并显示在屏幕上; 5) 等待从管道中读出子进程2写入的数据,并显示在屏幕上; 6) 退出。 子进程: 1) 将管道的写入口加锁; 2) 将信息“Child process n is sending message!”输入到变量OutPipe中,n=1,2; 3) 将OutPipe中信息写入管道; 4) 睡眠等待; 5) 将管道的写入口解锁; 6) 退出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值