Linux 进程间通信(system v 信号灯+system v 共享内存

系统V共享内存原理

进程间需要共享的数据被放在一个叫做IPC共享内存区域的地方,所有需要访问该共享区域的进程都要把该共享区域映射到本进程的地址空间中去。系统V共享内存通过shmget获得或创建一个IPC共享内存区域,并返回相应的标识符。内核在保证shmget获得或创建一个共享内存区,初始化该共享内存区相应的shmid_kernel结构注同时,还将在特殊文件系统shm中,创建并打开一个同名文件,并在内存中建立起该文件的相应dentry及inode结构,新打开的文件不属于任何一个进程(任何进程都可以访问该共享内存区)。

信号灯与其他进程间通信方式不大相同,

它主要提供对进程间共享资源访问控制机制。相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,同时,进程也可以修改该标志。除了用于访问控制外,还可用于进程同步。信号灯有以下两种类型:

二值信号灯:最简单的信号灯形式,信号灯的值只能取0或1,类似于互斥锁。
注:二值信号灯能够实现互斥锁的功能,但两者的关注内容不同。信号灯强调共享资源,只要共享资源可用,其他进程同样可以修改信号灯的值;互斥锁更强调进程,占用资源的进程使用完资源后,必须由进程本身来解锁。

计算信号灯:信号灯的值可以取任意非负值(当然受内核本身的约束)。

/*

*
 *       Filename:  producer.c
 *
 *    Description:  生产者进程
 *
 *        Version:  1.0
 *        Created:  09/30/2011 04:52:23 PM
 *       Revision:  none
 *       Compiler:  gcc(g++)
 *
 *         Author:  |Zhenghe Zhang|, |zhenghe.zhang@gmail.com|
 *        Company:  |Shenzhen XXX Technology Co., Ltd.|
 *
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>

#define MAXSHM      5  //定义缓冲区数组的下标变量个数

union semun {
int val; /* value for SETVAL */
struct semid_ds *buf;/* buffer for IPC_STAT & IPC_SET */
unsigned short *array;/* array for GETALL & SETALL */
struct seminfo *__buf;/* buffer for IPC_INFO */
void *__pad;
};

int main()
{
    key_t ipckey;
    key_t semkey;

int shmid;
    char *addr_c;

/* 定义信号灯集,该信号灯集包含3个信号量 fullid, emptyid, mutexid  */
    int semid;

ipckey = ftok("/home/zhang/shmipcx", 10001);
    if(ipckey == -1)
    {
        perror("ftok");
        exit(1);
    }
 
    shmid = shmget(ipckey, 1024, IPC_CREAT | 0666);
    if(shmid == -1)
    {
        perror("shmget");
        exit(1);
    }

addr_c = (char*)shmat(shmid, NULL, 0);
    if(*((int*)addr_c) == -1)
    {
        perror("shmat");
        exit(1);
    }

/* 定义信号量数据结构 */
    struct sembuf  P,V;
    union semun arg1, arg2, arg3;

semkey = ftok("/home/zhang/shmipcy", 10001);
    if(semkey == -1)
    {
        perror("ftok");
        exit(1);
    }

/* 创建信号灯集  */
    semid  = semget(semkey, 3, IPC_CREAT | 0666); //如果创建新集合(一般在服务器进程中), 则必须指定nsems
    if(semid < 0)
    {
        perror("semget semid");
        exit(1);
    }

/*初始化信号灯集中的信号量 */
    arg1.val = 0;            //初始时缓冲区中无数据 (fullid, 缓冲区满信号量)
    if(semctl(semid, 0, SETVAL, arg1) == -1)
    {
        perror("semctl setval error");
        exit(1);
    }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/23342.html