Unix环境进程间通信(一)

原创 2006年05月26日 08:46:00

1.1        信号量

SystemV的信号量使用方法

1.1.1   数据结构

include <sys/types.h>

include <sys/ipc.h>

include <sys/sem.h>

1.

struct semid_ds{     /* 通道结构 */

struct ipc_perm  sem_perm;

       struct sem  *sem_base;      /* 指向信号量数组,系统内部使用,用户不能直接访问*/

       ushort      sem_nsems;     /* 信号量个数 */

time_t      sem_otime;     /* 最后semop时间 */

time_t      sem_ctime;     /* 最后修改时间 */

}

2.

struct sem {               /* 信号量的成分 */

ushort semval;                   /*非负值*/

ushort sempid;                   /*最后semoppid*/

ushort semncnt;                  /*等待semval增加的进程数*/

ushort semzcnt;                  /*等待semval0的进程数*/        

}

3.

semctl函数需要的联合体:

 

#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)

       /* union semun is defined by including <sys/sem.h> */

#else

       /* according to X/OPEN we have to define it ourselves */

       union semun {

             int val;                    /* 用于 SETVAL 命令*/

             struct semid_ds *buf;     /* 用于 IPC_STAT, IPC_SET */

             unsigned short *array;    /* 用于 GETALL, SETALL 命令,存放所获得的或要设置的信号量集合中所有信号量的值*/

                    /* Linux specific part: */

             struct seminfo *__buf;    /* 用于 IPC_INFO */

       };

#endif

4.

struct sembuf {      /* 操作数数组成员结构,用于semop函数*/

              ushort sem_num;        /* 信号量编号 */

              short   sem_op;        /* 操作数 */

              short   sem_flag;      /* 操作标志 */

}

 

1.1.2   API

4.1 #include <semaphore.h>

信号量集合初始化,建立信号量集合标识及相连的数据结构

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

返回:成功返回信号量集合id,错误返回-1并设置errno

第一个参数keyIPC关键字。它有特殊值IPC_PRIVATE表示总是创建一个私有信号量集合。

第二个参数指明信号量集合中信号量的个数。nsems必须大于0小于系统在头文件<sys/sem.h>中定义的信号量最大值宏SEMMSL。当信号量集合已经存在时,此参数必须合法,即为大于0小于该信号量集合的个数,或简单设为0。信号量的编号,第一个是0最后一个是nsems-1

key值不等于IPC_PRIVATE时,semget动作取决于最后一个参数semflag标志:

IPC_CREAT 单独设置此标志,当系统中不存在相同key时,创建一个新的信号量集合,否则返回已存在的信号量集合标识。

IPC_EXCL 单独设置不起作用。与 IPC_CREAT同时设置时,当系统中存在相同key时,错误返回。保证不会打开一个已存在的信号量集合。

此函数只能创建一个信号量集合,集合中的每个信号量没有初始化,这要用4.2函数。

可重用包装函数:

//打开或创建信号量集合,权限参数必须是型如"066"的字符串

int open_semaphore_set(key_t key_val, int num_sems, char* mode_str) {

       int sid;
       int mode;

       if (mode_str != NULL) {
              sscanf(mode_str, "%o", &mode);
       } else {
              mode = 0660;
       }

       if(!num_sems) {
              return (-1);
       }

       if ((sid = semget(key_val, num_sems, mode | IPC_CREAT)) == -1)
              return (-1);
       else
              return sid;
}

 

 

4.2 #include <sys/types.h>

   #include <sys/ipc.h>

   #include <sys/sem.h>

信号量控制函数

int semctl(int semid, int semnum, int cmd, ...);

返回:失败-1, 成功对于命令GETVAL,GETPID,GETNCNT,GETZCNT返回相应值,其他命令返回0

1个参数semid必须是一个合法的信号量集合标识。

2个参数semnum选择集合中一个特定的信号量,

3个参数给出操作命令,第4 参数给出相应命令所需的参数,此参数可选:

CMD

说明

参数

SETVAL

设置semid信号量集合中的semnum信号量semvalarg.val。同时更新semid_ds中的sem_ctime成员。

arg.val

GETALL

返回信号量集合中所有信号量的值

arg.array

SETALL

设置信号量集合中所有信号量的值

arg.array

IPC_STAT

放置与信号量集合相连的semid_ds结构当前值于arg.buf指定的缓冲区

arg.buf

IPC_SET

arg.buf指定的结构值代替与信号量集合相连的semid_ds结构值

arg.buf

GETVAL

系统调用,返回信号量集合重的semnum信号量的值semval

 

GETPID

返回最后一个操作该信号量集合的进程ID

 

GETNCNT

返回semncnt的值

 

GETZCNT

返回semzcnt的值

 

IPC_RMID

删除制定的信号量集合

 

 

可重用包装函数:

//获得指定的信号量的值

int get_sem_val(int sid, int semnum) {

       return semctl(sid, semnum, GETVAL, 0);

}

 

//给指定的信号量赋初值

void init_a_semaphore(int sid, int semnum, int initval) {

       union semun semopts;
       semopts.val= initval;
       semctl(sid, semnum, SETVAL, semopts);
}

 

//给指定的信号量集合赋初值

void init_all_semaphore(int sid, int val_array[]) {

       union semun semopts;
       semopts.array= (short unsigned int *)val_array;
       semctl(sid, 0, SETALL, semopts.array);
}

 

//改变信号量集合的访问权限,权限参数必须是型如"066"的字符串

int changemode(int sid, char *mode) {

       int rc;
       union semun semopts;
       struct semid_ds mysemds;

       semopts.buf= &mysemds;

       if ((rc = semctl(sid, 0, IPC_STAT, semopts)) == -1)
              return -1;
       sscanf(mode, "%o", &semopts.buf->sem_perm.mode);
       return semctl(sid, 0, IPC_SET, semopts);
}

 

//删除指定的信号量集合

int rm_semaphore(int sid) {

       return semctl(sid, 0, IPC_RMID, 0);

}

 

 

4.3 #include <sys/types.h>

   #include <sys/ipc.h>

   #include <sys/sem.h>

信号量操作函数

int semop(int semid, struct sembuf *sops, unsigned nsops);

返回:失败-1,

1个参数指明信号量集合标识,

2个参数sops指向一个类型为sembuf的结构数组

3个参数nsops给出该数组元素个数。取值范围0SEMOP

此函数对制定的信号量集合进行操作,操作既可以针对单个信号量,也可一对整个信号量集合进行操作。操作的信号量对象和操作动作由sops指向的结构体指出:

struct sembuf {      /* 操作数数组成员结构,用于semop函数*/

              ushort sem_num;        /* 信号量编号 */

              short   sem_op;        /* 操作数 */

              short   sem_flag;      /* 操作标志 */

}

sem_num指出信号量编号。

sem_op给出操作的类型:

1.< 0 减少一个信号量的值,减少为abs(sem_op)。这相当与请求信号量所控制的资源。当为-1时, 相当于P操作。当信号量当前值>=abs(sem_op),操作成功,否则当没有设置标志IPC_NOWAIT时,进程将等待直到信号量的当前值>=abs(sem_op)

2.>0 增加一个信号量的值,增加为sem_op。相当于返回信号量控制的资源。当为1时,相当于V操作。

3.=0 等待信号量变为0。对应于等待信号量控制的所有资源均可以用。如果信号量已经为0,调用立即返回;否则没有设置IPC_NOWAIT时,调用被阻塞。

sem_flag对操作进行适当控制:

       1. IPC_NOWAIT 如果设置,当指定的操作不能完成时,进程将不等待立即返回-1,且设置errnoEAGAIN

       2.SEM_UNDO 如果设置,当进程退出时,进行信号量解除(UNDO)操作。注意,设置此值后,对信号量进行相反操作的动作也要设置(UNDO)操作。

可重用包装函数:

int semaphore_P(int sem_id) {

       struct sembuf sb;

       sb.sem_num = 0;
       sb.sem_op = -1;

       sb.sem_flg = SEM_UNDO;

       if (semop(sem_id, &sb, 1) == -1) {

              fprintf(stderr, "semaphore_p failed/n");

              return (0);
       }

       return 1;

}

 

int semaphore_V(int sem_id) {

       struct sembuf sb;

       sb.sem_num = 0;
       sb.sem_op = 1;

       sb.sem_flg = SEM_UNDO;

       if (semop(sem_id, &sb, 1) == -1) {

              fprintf(stderr, "semaphore_v failed/n");
              return (0);
       }

       return 1;
}

1.1.3   Example

int main(int argc, char** argv) {

       int sem_id;

       int i, creat = 0;
       int pause_time;
       char* cp;

       //以进程id作为随机数种子
       srand((unsigned int)getpid());

      
       //打开/创建仅一个信号量的初值为1

       sem_id = open_semaphore_set((key_t)1234, 1, “0660”);

       if (argc > 1 && strcmp(argv[1], "1")) {
              init_a_semaphore(sem_id, 0, 1);
              creat = 1;
              sleep(2);
       }

       for(i = 0; i < argc; i++) {
              cp = argv[i];
              if (!semaphore_p(sem_id))
                     exit(EXIT_FAILURE);
              printf("process %d", getpid());
              fflush(stdout);
              while(*cp) {
                     printf("%c", *cp);
                     fflush(stdout);
                     pause_time = rand() %3;
                     sleep(pause_time);
                     cp++;
              }
       }
       printf("/n%d -finished/n", getpid());

       if (creat == 1) {
              sleep(10);
              rm_semaphore(sem_id);
       }
       exit(EXIT_SUCCESS);
}

UNIX环境高级编程(第15章 进程间通信)

进程间通信的方式包括管道、消息队列、信号量和共享存储。通过这些机制,同一台计算机上运行的进程可以互相通信。...
  • lincoln_2012
  • lincoln_2012
  • 2015年06月30日 10:12
  • 590

【Unix编程】进程间通信(IPC)

Linux进程间通信(IPC) 进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。IPC的方式通常有管道(包括无名管道和命名管道)、消息队列...
  • lisong694767315
  • lisong694767315
  • 2015年04月21日 20:42
  • 1403

UNIX网络编程——进程间通信

进程间通信,Interprocess Communication,IPC 1、管道和FIFO (1)管道的根本局限在于没有名字,从而只能由有亲缘关系的进程使用。FIFO也叫有名管道,解决了这个限制。...
  • songshiMVP1
  • songshiMVP1
  • 2016年07月27日 19:53
  • 302

Unix系统下进程间通信方式及比较

本文转载自: 进程间的通信方式:    1.管道(pipe)及有名管道(named pipe):      管道可用于具有亲缘关系进程间的通信,有名管道除了具有管道所具有的功能外,它还允许无...
  • CYXLZZS
  • CYXLZZS
  • 2014年08月27日 14:34
  • 6610

Unix下管道实现进程间通信

1.进程间利用管道通信的应用场景主要是数据传输:一个进程需要将数据发送给另外一个进程;2. 管道通信:一个进程在管道的尾部写入数据,另一个进程从管道的头部读出数据。管道包括无名管道和有名管道两种,前者...
  • u010853261
  • u010853261
  • 2016年12月05日 12:39
  • 835

《unix高级环境编程》进程间通信——共享内存

共享内存是允许两个或多个进程共享同一块内存区域
  • chenhanzhun
  • chenhanzhun
  • 2014年11月18日 16:13
  • 1321

UNIX/Linux进程间通信IPC---管道--全总结(实例入门)

管道 一般,进程之间交换信息的方法只能是经由fork或exec传送打开文件,或者通过文件系统。而进程间相互通信还有其他技术——IPC(InterProcessCommunication) (因为不同的...
  • yang_yulei
  • yang_yulei
  • 2013年12月18日 23:02
  • 2561

进程间通信方式有哪些?各自有哪些优缺点?

1)管道 管道分为有名管道和无名管道 无名管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系一般指的是父子关系。无明管道一般用于两个不同进程之间的通信...
  • xinianbuxiu
  • xinianbuxiu
  • 2017年01月15日 16:18
  • 3739

详谈UNIX环境进程异常退出

简介:本文详细论述UNIX环境上的进程异常退出,将导致进程异常退出的各种情景归纳为两类,对每类情况详细分析了问题出现的根本原因,同时添加了相应的实例以易于您更好地进行了解。在此基础上,文章最后论述了应...
  • zhangfulin_hwatop
  • zhangfulin_hwatop
  • 2013年02月03日 18:26
  • 1874

unix进程通信方式总结(下)

在前两篇博客http://blog.csdn.net/caoyan_12727/article/details/52049417和http://blog.csdn.net/caoyan_12727/a...
  • caoyan_12727
  • caoyan_12727
  • 2016年08月10日 19:08
  • 1722
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Unix环境进程间通信(一)
举报原因:
原因补充:

(最多只允许输入30个字)