Linux C编程之进程间通信

本文详细介绍了Linux系统中进程间通信的四种主要方法:匿名管道、命名管道(FIFO)、消息队列和共享内存。对于每种方法,都阐述了其基本概念、操作步骤和示例代码,展示了如何创建、读写和管理这些通信机制。此外,还涉及到了信号量作为同步工具的应用。
摘要由CSDN通过智能技术生成

进程间通信(IPC),就是在不同进程之间传播或交换信息,Linux进程间通信的方法有:管道,消息队列,信号量,共享内存,套接字等等。

目录

一,管道

     1,匿名管道

管道的读写:

2,命名管道

二,消息队列

 1,消息队列概念

2,消息队列的创建与打开

3,消息队列的读写

4,获得或设置消息队列的属性

三,共享内存

共享内存相关操作:

1,创建或者打开共享内存:

2,附加:

3,分离

4,共享内存的控制

实例:使用共享内存完成父子进程之间的通信 

四,信号量

 信号量的相关操作

1,创建或者打开信号量集

2,对信号量集的操作

3,对信号量集的控制

例程,使用信号量完成进程间的同步:


一,管道

     1,匿名管道

匿名管道在系统中没有实名的,并不刻意在文件系统中以任何方式看到该管道,它只是进程的一种资源,会随着进程的结束而被系统清理掉。管道通信是半双工的,需要双向通信时,需要建立起两个管道,只能由于父子或者兄弟进程之间,管道的缓冲区是有限的,定义大小为PIPE_BUF(usr/include/linux/limits.h)4096字节。

       #include <unistd.h>

       Int pipe(int pipefd[2]) ;

成功返回0,出错返回-1,fd[2]是返回的两个文件描述符。fd[0]表示读出端的文件描述符。fd[1]表示写入端的文件描述符。

例如pipe.c:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/stat.h>
int main()
{
pid_t pid;
int fd[2];
pipe(fd);     //在fork()之前
printf("fd[0]=%d\n",fd[0]);
printf("fd[1]=%d\n",fd[1]);
if((pid=fork())==-1)
{
printf("error\n");
exit(1);
}
else if(pid==0)
{
}
else
;
return 0;
}

管道的读写:

   可以使用read和write函数进行读写操作读取规则为:管道写端不存在时,认为读到了末尾,读出字节数为0。

如下: 先创建管道,父进程写入数据,子进程读取数据:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
int fd[2];
char buf[32]={0};
pipe(fd);
printf("fd[0]=%d\n",fd[0]);
printf("fd[1]=%d\n",fd[1]);
if((pid=fork())==-1)
{
printf("error\n");
exit(1);
}
//子进程
else if(pid==0)
{   
    close(fd[1]);
	read(fd[0],buf,32);
   printf("buf is %s\n",buf);
	close(fd[0]);
	exit(0);
}
else  //父进程
{  
   close(fd[0]);
   int status;
   write(fd[1],"hello Linux",11);
   close(fd[1]);
   wait(&status);
   exit(0);
}
return 0;
}

如下:在兄弟进程间创建管道实现通信:

  在父进程fork两个子进程,fork()出子进程后,子进程继承存活的故拿到,故第二个fork()才关闭父进程中关闭管道输出:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <limits.h>

#define BUFSIZE PIPE_BUF

void err(char *msg)
{
printf("%s\n",msg);
exit(1);
}

int main()
{
int len=0;
int fd[2];
pid_t pid1,pid2;
char buf[BUFSIZE]="hello my brother\n";
if(pipe(fd)<0)
		err("pipe failed");

if((pid1=fork())<0)
		err("fork_1 failed");
if(pid1==0)  //子进程1
{
   close(fd[0]);
   write(fd[1],buf,strlen(buf));
   close(fd[1]);
    exit(0);

}
if((pid2=fork())==-1)
		err("fork_2 failed");
if(pid2==0)  //子进程2
{    
   close(fd[1]);
  len= read(fd[0],buf,BUFSIZE);
  write(STDOUT_FILENO,buf,len);  //标准输出
  close(fd[0]);
   exit(0);
}
else
{
close(fd[0]);
close(fd[1]);
exit(0);
}

return 0;
}

输出结果如下: 

2,命名管道

 命名管道也成为FIFO,,不同于匿名管道,它是一种文件类型,在文件系统中是可见的,命名管道可以在无亲缘关系的进程之间通信,FIFO严格遵守先进先出规则,不支持lseek文件定位操作。

在shell中可以使用mkfifo命令创建一个命名管道:

mkfifo [options] name

options: -m mode 设置文件权限,受umask修正

c程序创建:

 #include <sys/types.h>

 #include <sys/stat.h>

 int mkfifo(const char* pathname,mode_t mode);

pathname文件路径,mode权限,成功返回0,出错返回-1。

如下所示: 创建fifo_write.c和wifi_read.c。执行是fifo_write.c进程创建命名管道并写入内容,fifo_read.c进程读取内容,并输出:

fifo_write.c:

1.#include <stdio.h>
2.#include <unistd.h>
3.#include <sys/types.h>
4.#include <stdlib.h>
5.#include <sys/stat.h>
6.#include <sys/wait.h>
7.#include <fcntl.h>
8.#include <string.h>
9.
10.int main(int argc,char *argv[])
11.{
12.int fp;
13.int ret;
14.//以规定格式打开
15.if(argc!=2)
16.{
17.   printf("Format: %s <fifo name>\n",argv[0]);
18.   return -1;
19.}
20.//如果该管道文件没有被创建,则创建
21.//access 参数二为F_OK时,返回-1表示参数一指定的文件不存在
22.if(access(argv[1],F_OK==-1))
23.{
24.  ret=mkfifo(argv[1],0666);
25.     if(ret==-1)
26.            {
27.    printf("make fifo error\n");
28.    return -2;
29.   }
30.   printf("mkfifo is ok\n");
31.}
32.//以只写的方式打开该文件
33.fp=open(argv[1],O_WRONLY);
34.while(1)
35.{
36.   sleep(1);
37.   write(fp,"Linux haihaihai",15);
38.}
39.close(fp);
40.return 0;
41.}

fifo_read.c: 

1.#include <stdio.h>
2.#include <unistd.h>
3.#include <sys/types.h>
4.#include <stdlib.h>
5.#include <sys/stat.h>
6.#include <sys/wait.h>
7.#include <fcntl.h>
8.#include <string.h>
9.
10.int main(int argc,char *argv[])
11.{
12.
13.char buf[32]={0};
14.int ret;
15.int fp;
16. //按规定格式输入
17. if(argc!=2)  
18. {
19.   printf("Format: %s <fifo name>\n",argv[0]);
20.   return -1;
21. }
22.//以只读的方式打开管道文件
23.fp=open(argv[1],O_RDONLY);  
24.while(1)
25.{
26.   sleep(1);
27.   read(fp,buf,32);
28.   printf("buf is %s\n",buf);
29.   memset(buf,0,sizeof(buf));
30.}
31.close(fp);
32.return 0;
33.}

用两个终端分别运行程序:fifo_write进程每隔1s把"Linux haihaihai"写进管道,fifo_read进程每隔1s从管道中读取并标准输出到屏幕:

二,消息队列

 1,消息队列概念

        消息队列是一种以链表式结构组织的数据,存放在内核中,是由各进程通过消息队列标识符来引用的一种数据传送方式,消息队列是随内核持续的,即只有在内核重启或者显示删除一个消息队列时,该消息队列才会被真正删除,系统中有记录消息队列的数据结构(struct ipc_ids msg_ids)位于内核中,系统中的所有消息队列都可以在结构msg_ids中找到访问入口。

        消息队列就是一个消息的链表,每个消息队列都有一个队列头,用结构struct msg_quene来描述,该队列头包含了消息的大量信息,包括消息的队列键值,用户ID,组ID,消息数目等等,用户可以访问也可以设置这些信息,该结构体定义如下:

struct msg_quene

{

struct ipc_perm q_perm;

item_t q_stime;       //上次发送时间

item_t r_stime;      //上次接收时间

item_t c_stime;

unsigned long q_cbytes;               //队列中当前字节

unsigned long q_cnum;                  //消息数量

unsigned long q_qbytes;                //最大字节数

pid_t lspid;                                     //pid of last msgsnd

pid_t lrpid;                                      //last receive pid

struct list_head q_messages;

struct list_head q_receivers;

struct list_hesd q_senders;

}

结构msqid_ds用来设置或者返回消息队列的信息:

struct msqid_ds

{

struct ipc_perm q_perm;

struct msg* msg_first;

struct msg* msg_last;

item_t q_stime;    

item_t r_stime;    

item_t c_stime;

unsigned long msg_lcbytes;    

unsigned long msg_lqbytes;    

unsigned short msg_cbytes;    

unsigned short msg_qnum; 

unsigned short msg_qbytes; 

pid_t msg_lspid;

pid_t msg_lrpid;

}

struct ipc_perm定义如下:

struct ipc_perm

{

key_t key;    //该键值唯一对应一个消息队列

uid_t uid;   

gid_t gid;

uid_t cuid;

gid_t cgid;

mode_t mode;

unsigned long seq;

};

2,消息队列的创建与打开

每个消息队列都有一个标识符,而要获取标识符,首先要提供该消息队列的键值。ftok函数用于获取特定文件名的键值。

#include <sys/types.h>

#include <sys/ipc.h>

key_t ftok(char * pathname,char proj);

成功返回键值,出错返回-1,pathname是一个路径于该键值对应。

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgget(key_t key,int msgflg);

msgget函数用来创建或者打开与键值对应的消息队列,成功返回标识符,出错返回-1,key是键值,msgflg参数是标志位,可取以下值:IPC_CREAT,IPC_EXCL,IPC_NOWAIT或三者逻辑或的结果。msgget创建时,它相应的msqid_ds被初始化,ipc_perm结构各成员被设置成特定值。以下情况时,创建新的消息队列:

        无消息队列与key对应,且设置了IPC_CREAT标志位;

        key设置为IPC_PRIVATE。

3,消息队列的读写

        消息队列传递的消息由两部分组成,消息的类型和所传递的数据,一般用数据结构struct msgbuf来表示,通常类型是一个长整数,数据根据需要进行设定,如:

struct msgbuf

{

long msgtype;   //传递数据的类型

char msgtext[1024];

}

向消息队列发送数据系统调用函数原型如下:

#include <sys/types>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgsnd (int msqid,const void *ptr,size_t nbytes,int flags);

成功返回0,出错返回-1。msgsnd函数向消息队列发送一个消息,该消息被添加到队列的末尾,msqid代表队列标识符,ptr指向要发送的消息,nbytes以字节数表示消息数据的长度,flags用于指定队列满时的处理方法,当flags设置为IPC_NOWAIT时,表示队列满时不等待直接返回一个错误。

从消息队列中接收一个数据函数如下:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgrcv (int msqid,const void *ptr,size_t nbytes,long type,int flags);

成功返回消息的数据长度,出错返回-1,该函数用来读取一个消息的数据。其参数类似于msgsnd。type取0时,接收队列中第一条消息,取值大于0时,接收队列中类型值等于type的第一条消息,小于0时,取类型值小于等于type的绝对值的所有消息中类型值最小的那一条消息。

4,获得或设置消息队列的属性

        消息队列的属性基本上都保存在队列头上,可以分配一个类似于队列头的结构体来返回队列的属性。

int msgctl(int msqid,int cmd,struct msqid_ds *buf);

 成功返回0,失败返回-1,cmd取值有:

        IPC_STAT:获取队列信息,返回的信息存储在buf中;

        IPC_SET:设置队列信息;

        IPC_RMID:删除msqid标识的消息队列。

例子程序如下:msg.c:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <unistd.h>

void msg_stat(int msgid,struct msqid_ds msg_info);

int main()
{
	int gflags,sflags,rflags;
	key_t key;
	int msgid;
	int reval;
  //发送消息缓冲区数据结构
	struct msgsbuf    
	{ 
		int mtype;
		char mtext[1];
	}msg_sbuf;
  //接收消息缓冲区数据结构
	struct msgmbuf
	{
	    int mtype;
		char mtext[10];
	}msg_rbuf;
	struct msqid_ds msg_ginfo,msg_sinfo;
	char* msgpath="./msgqueue";
	key=ftok(msgpath,'a');
	gflags=IPC_CREAT|IPC_EXCL;
	msgid=msgget(key,gflags|00666);
	if(msgid==-1)
		{
		printf("msg creat error!\n");
		return -1;
		}
	msg_stat(msgid,msg_ginfo);
	
	sflags=IPC_NOWAIT;
	msg_sbuf.mtype=10;
	msg_sbuf.mtext[0]='a';
	reval=msgsnd(msgid,&msg_sbuf,sizeof(msg_sbuf.mtext),sflags);
	if(reval==-1)
		{
		  printf("msg send error!\n"); 
	        }
	msg_stat(msgid,msg_ginfo);
	
	rflags=IPC_NOWAIT|MSG_NOERROR;
	reval=msgrcv(msgid,&msg_rbuf,4,10,rflags);
	if(reval==-1)
		{
		printf("resd msg error!\n");
		}
	else
		{
		printf("read from msg queue %d bytes\n ",reval);
		}
	msg_stat(msgid,msg_ginfo);
	
	msg_sinfo.msg_perm.uid=8;
	msg_sinfo.msg_perm.gid=8;
	msg_sinfo.msg_qbytes=16388;
	
	reval=msgctl(msgid,IPC_SET,&msg_sinfo);
	if(reval==-1)
		{
		printf(" msg set info error!\n");
		return -2; 
		}
	msg_stat(msgid,msg_ginfo);
	
	reval=msgctl(msgid,IPC_RMID,NULL);
	if(reval==-1)
		{
		printf(" unlink msg queue error!\n");
		return -3;
		}
	return 0;
}





void msg_stat(int msgid,struct msqid_ds msg_info)
{
	int reval;
	sleep(1);
	reval=msgctl(msgid,IPC_STAT,&msg_info);
		if(reval==-1)
		{
		  printf("get msg info error\n");
		  return;
		}
        printf("\n");
        printf("current number of bytes on queue is %ld\n",msg_info.msg_cbytes);
        printf("number of messages in queue is %ld\n",msg_info.msg_qnum);
        printf("max number of bytes on queue is %ld\n",msg_info.msg_qbytes);
        printf("pid of last msgsnd is %d\n",msg_info.msg_lspid);
        printf("pid of last msgrcv is %d\n",msg_info.msg_lrpid);
        printf("last msgsnd time is %s",ctime(&(msg_info.msg_stime)));
        printf("last msgrcv time is %s",ctime(&(msg_info.msg_rtime)));
        printf("last change time is %s",ctime(&(msg_info.msg_ctime)));
        printf("msg uid is %d\n",msg_info.msg_perm.uid);
        printf("msg gid is %d\n",msg_info.msg_perm.gid);
}
        
        
        

如下,用root权限运行,但是发现读取时发生了错误,目前不知道什么原因。

三,共享内存

        两个不同的进程共享内存的意思是,同一块物理内存被映射到两个进程各自的进程地址空间,在shell可以使用ipcs查看当前系统IPC的状态。

  对每一个共享存储段,内核会为其维护一个shmid_ds的数据类型的结构体(shmid_ds结构体定义在头文件<sys/shm.h>中),其定义如下:

struct shmid_ds

{

struct ipc_perm q_perm;

size_t shm_segzs;             //字节表示共享内存的大小

pid_t shm_lpid;               //最近一次调用shmop函数的进程ID  

pid_t shm_cpid;               //创建该共享内存的进程ID

unsigned short shm_lkcnt;     //共享内存区域被锁定的时间数    

unsigned long shm_nattch;   //当期使用该共享内存的进程数 

time_t shm_atime;      //最近一次附加操作时间

time_t shm_dtime;      //最近一次分离操作时间

time_t shm_ctime;     //最近一次修改时间

};

共享内存相关操作:

对于System V共享内存,主要有几个API,shmget,shmat,shmdt,shmctl。

1,创建或者打开共享内存:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

int shmget(key_t key,int size,int flag)

成功返回共享内存ID,出错返回-1。key表示所要创建或者打开共享内存的键值,size表示共享内存区域的大小,flag表示调用函数的操作类型,也可用于设置共享内存的访问权限,两者通过逻辑或来实现。

当key指定为IPC_PRIVATE时,创建一个新的共享内存,此时flag无效;

当key不为PC_PRIVATE且flag设置了IPC_CREAT位而没有IPC_EXCL位时,若key存在,则打开其对应的共享内存,否则则创建共享内存。

当key不为PC_PRIVATE且flag设置了IPC_CREAT位和IPC_EXCL位时,只执行创建共享内存的操作,key与内核中已经存在的共享内存的键值都不同时,才创建成功,否则返回EEXIST错误。

如下,创建共享内存:creat_shm.c:

#include <sys/ipc.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/shm.h>
int main()
{
int shmid;
shmid=shmget(IPC_PRIVATE,1024,0666);
if(shmid<0)
{
printf("creat shm err!");
return -1;
}
printf("creat successfully and shmid is %d\n",shmid);
//使用shell命令查看
system("ipcs -m");

return 0;
}

执行结果如下:

使用宏IPC_CREAT创建得到键值为0,而使用ftok得到的键值传入该参数,键值不为0。

2,附加:

当一个共享内存被创建或打开后,某个进程如果要使用共享内存,必须将此内存区域附加到他的地址空间,附加的系统调用如下:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

void * shmat(int shmid,const void* addr,int flag);

成功返回指向共享内存段的指针,出错返回-1。

shmid指定要引入的共享内存ID,addr和flag说明要引入的地址值,addr为NULL时,表示有内核决自动完成地址得映射。 执行成功后,shmid_ds结构体的shm_nattch值加一。

3,分离

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

int shmdt(void* addr);

成功返回0,否则返回-1。

将进程地址映射解除,即用于共享内存的区域与进程的地址空间相分离,addr是调用函数的返回值,并不删除共享内存本身。

4,共享内存的控制

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

int shmctl(int shmid,int cmd,struct shmid_ds *buf)

成功返回0,否则返回-1。

shmid表示共享内存ID,buf作用与cmd相关,cmd取值如下:

IPC_STAT :  获取共享内存shmid_ds结构,返回给buf;

IPC_SET : buf赋值给共享内存的shmid_ds结构;

IPC_RMID:删除shmid指向的共享内存段;

IPC_LOCK,IPC_UNLOCK:...

实例:使用共享内存完成父子进程之间的通信 

creat_shm_2.c如下:

#include <sys/ipc.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>


int main()
{
char * addr_w,*addr_r;
int shmid;
int key;
pid_t pid;

key=ftok("./shm_space",25);    //获取键值

shmid=shmget(key,1024,IPC_CREAT|0777);
if(shmid<0)
{
printf("creat shm err!");
return -1;
}
printf("creat successfully and shmid is %d\n",shmid);

pid=fork();

if(pid==0)   //子进程读取共享内存数据
{ 
   sleep(2);
   printf("child process\n");
   addr_r=shmat(shmid,NULL,0);
   printf("receive massage is %s\n",addr_r);

}
else if(pid>0)   //父进程向共享内存中写入数据
{
    addr_w=(char*)shmat(shmid,NULL,0);
    strncpy(addr_w,"This is a test",14);
    wait(NULL);
    exit(0);
}
else
{
printf("fork error!");
exit(1);
}

return 0;
}


执行结果如下:

四,信号量

信号量的原理是一种数据操作锁的概念,它本身不具备数据交换的功能,而是通过其他通信资源来实现进程之间的通信。在信号量上定义两种操作,Wait和Release,当一个进程调用Wait等待时,它要吗得到的信号量得值减一,要吗一直等待下去,直到信号量大于1时,Release实际上在信号量上执行加一操作,释放信号量守护的资源。

        在信号量的实际应用中,不能单独定义一个信号量,而是定义一个信号量集,其中包含一组信号量,同一信号量只使用同一个引用ID,每个信号量集都有一个与之对应的结构体:

struct semid_ds

{

struct ipc_perm sem_perm;  

struct sem* sem_base;

unsigned short sem_nsems;

time_t sem_otime;

time_t sem_ctime;

};

 其中sem结构体如下,记录了一个信号的信息:

struct sem

{

unsigned short semval;   

pid_t sempid;

unsigned short semncent;

unsigned short semncent;

};

 信号量的相关操作

1,创建或者打开信号量集

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

int semget(key_t key,int nsems,int flag);

成功返回信号量集ID,否则返回-1。

该函数用于创建或者打开信号量集,key表示对应的键值,nsems表示信号量集中包含信号的个数,此参数只在创建信号量集时有效,flag表示调用函数的操作类型和权限,用逻辑或实现,约定与shmget类似。若使用该函数创建一个新的信号量集时,相应的semid_ds被初始化。

2,对信号量集的操作

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

int semop(int semid,struct sembuf semoparray[],size_t nops);

 成功返回0,失败返回-1。

semid表示信号量集的ID,nops表明semoparray数组的个数,sembuf结构体定义如下(原子操作):

struct sembuf

{

unsigned short sem_num;

short sem_op;

short sem_flg;

}

sem_num表示信号量中某一个资源(要指定的信号量),取值范围为0-ipc_perm.sem_nsems,

sem_op指向执行的操作,其取值为整数。sem_flg说明函数semop的行为:

sem_op>0时,进程对该资源使用完毕,释放相应的资源数,并将sem_op的值加到信号量上。

sem_op=0时,进程阻塞直到相应值为0,当信号量为0时,函数立即返回,如果信号量值不为0,依据sem_flag的IPC_NOWAIT位决定函数的动作。 

 sem_o<0时,请求sem_op绝对值得资源,如果相应资源数可以满足。则信号量的值减去sem_op的绝对值,函数成功返回,否则操作将与sem_flg有关。

3,对信号量集的控制

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

int semctl(int semid,int semnum,int cmd,union semun arg);

 函数成功返回值大于等于0,否则返回-1。

semnum指定semid的信号集中某一个信号量,cmd表示对应函数进行的操作,其取值与意义与arg有关,arg如下:

union

{

int val;

struct semid_ds* buf;

unsigned short array;

};

 cmd取值:

IPC_SET :按参数arg.buf的值设置信号两属性;

IPC_STAT: 获取信号量属性

IPC_RMID:删除信号量集

...

例程,使用信号量完成进程间的同步:

sem.c如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <unistd.h>

union semun    //定义结构体
{
	int val;
	struct semid_ds* buf;
	unsigned short array;
};

int main()
{
  int semid;
  int key;
  pid_t pid;
struct sembuf sem;
union semun sem_un;

  key=ftok("./sem_space",0666);          //获取键值
  semid=semget(key,1,0666|IPC_CREAT);   //创建信号集
  sem_un.val=0;                       
  semctl(semid,0,SETVAL,sem_un);          //信号量设置为0
  pid=fork();                            //创建子进程
   
/*
  子进程睡眠2s,父进程执行时,由于信号量为0,会被阻塞,子进程睡眠醒来之后
,释放信号量(V操作),此时父进程可以继续执行。

*/

  if(pid>0)
   {
    sem.sem_num=0;    
    sem.sem_op=-1;
    sem.sem_flg=0;
    semop(semid,&sem,1);
    printf("parents process\n");
    sem.sem_num=0;
    sem.sem_op=1;
    sem.sem_flg=0;
    semop(semid,&sem,1);
   }
   else if(pid==0)
   {
    sleep(2);   
    printf("child process\n");
    sem.sem_num=0;
	sem.sem_op=1;
	sem.sem_flg=0;
   semop(semid,&sem,1);
   }
return 0;
}

如下,通过信号量,实现量进程之间的同步操作:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值