信号量(semaphore)-创新互联

进程间通信-信号量

创新互联专注于彭阳网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供彭阳营销型网站建设,彭阳网站制作、彭阳网页设计、彭阳网站官网定制、微信平台小程序开发服务,打造彭阳网络公司原创品牌,更为您提供彭阳网站排名全网营销落地服务。

1、为什么要使用信号量

为了防止多个程序同时访问一个共享资源而引发的一系列问题,故有这样一种方法,在任何一个时刻只有一个执行线程访问代码的临界区(临界区是指访问临界资源的代码),而信号量就可以提供这样的访问机制,同一时刻只允许一个线程访问临界区,也就是说信号量是用来协调进程共享资源访问的,也就是说信号量用来协调进程对共享资源访问的,其中共享内存就是用信号量实现的。

2、信号量的工作原理

由于信号量只能进行两种操作等待和发送信号,他们是p(sv)操作,v(sv)操作。

p(sv)操作:如果sv的值大于0.他就减1,如果sv的值等于0,它就挂起进程的执行。

v(sv)操作:如果有其他进程因等待sv而挂起,则就让他恢复运行,如果没有进程因等待它而挂起,就让他加1.

举个例子,就是 两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,它将得到信号量,并可以进入临界区,使sv减1。而第二个进程将被阻止进入临界区,因为 当它试图执行P(sv)时,sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时第二个进程就可以恢复执行。

3、Linux信号量机制

Linux提供了一组精心设置的信号量接口来对信号量进行操作。这些函数都是用来对组的信号量进行操作,他们被声明在sys/sem.h中。

4、信号量的使用

(1)创建信号量

semget函数创建一个信号量集或者访问一个已存在的信号量集

int semget (key_t key, int nsem, int oflag)

返回值是一个称为信号量标识符的整数,semop和semctl函数将使用它。成功返回信号量的标示符,失败返回-1

key:由ftok()函数得到,

nsem:创建信号量中的个数

oflag:

    IPC_CREAT:若内核中不存在键值与key相等的信号量集,则创建,否则,返回此信号量集的标识符

  IPC_EXCL:单独使用无意义

  IPC_CREAT | IPC_EXCL :创建一个新的信号量集并返回信号量集的标识符,否则,返回-1.

(2)打开信号量(完成对信号量的PV操作)

用semget打开一个信号量后,对其中一个或多个信号量操作就是用semop来执行。

int semop (int semid, struct sembuf * opsptr, size_t nops)

    semid:信号量集标识符

  nsops:进行操作信号量的个数,即sops结构变量的个数,需大于或等于1.

    opspt:是一个指针,它指向一个信号量操作数组,信号量操作由sembuf结构表示

struct sembuf{
 short sem_num; // 除非使用一组信号量,否则它为0 
 short sem_op; // 信号量在一次操作中需要改变的数据,通常是两个数,
 // 一个是-1,即P(等待)操作,一个是+1,即V(发送信号)操作 
 short sem_flg; // 通常为SEM_UNDO,使操作系统跟踪信号,并在进程没有释放该信号量而终止时,
 // 操作系统释放信号量 
};

 当操作信号量(semop)时,flg可以设置SEM_UNDO标识;SEM_UNDO用于将修改的信号量值在进程正常退出(调用exit退出或main执行完)或异常退出(如段异常、除0异常、收到KILL信号等)时归还给信号量。进程以SEM_UNDO方式操作后;在进程未退出时,可以改变信号量的值,在进程退出时,将修改的值归还给信号量,信号量变成原来的值。

(3)在指定信号集或者信号集上的某个信号进行操作

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

    semid: 信号量集标识符

 semnum:信号量集数组上的下标,表示某一个信号量

第四个参数是可选的,取决于第个信号(操作对象)

参数cmd指定以下10种命令中的一种,在semid指定的信号量集合上执行此命令。

IPC_STAT  读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。

IPC_SET   设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。

IPC_RMID  将信号量集从内存中删除。

GETALL    用于读取信号量集中的所有信号量的值。

GETNCNT  返回正在等待资源的进程数目。

GETPID    返回最后一个执行semop操作的进程的PID。

GETVAL    返回信号量集中的一个单个的信号量的值。

GETZCNT  返回这在等待完全空闲的资源的进程数目。

SETALL    设置信号量集中的所有的信号量的值。

SETVAL    设置信号量集中的一个单独的信号量的值。

5.例子

comm.h

#define _PATH_NAME_ "/tmp"
#define _PROJ_ID_ 0x6666

int create_sem_set();

union semun
{
    int val;
    struct semid_ds* buf;
    unsigned short *array;
    struct eminfo*_buf;
};

int init_sem_set(int sem_id,int which,int val);
int create_sem_set(int nums);
int get_sem_set();

int destory_sem_set(int sem_id);

int P(int sem_id,int num);

int    V(int sem_id,int num);

comm.c

#include"comm.h"
static int comm_sem_set(int nums,int flags)
{
    key_t _key = ftok(_PATH_NAME_,_PROJ_ID_);
    if(_key<0)
    {
        perror("ftok");
        return -1;
    }
//    int sem_id = semget(_key,nums,IPC_CREAT |IPC_EXCL);
    int sem_id = semget(_key,nums,flags);
    if(sem_id <0)
    {
        perror("semget");
        return -2;
    }
    return sem_id;
}

int create_sem_set(int nums)
{
    int flags = IPC_CREAT | IPC_EXCL | 0666;
    return comm_sem_set(nums,flags);   
}

int get_sem_set()
{    
    int flags = IPC_CREAT;
    return comm_sem_set(0,flags);
}

int destory_sem_set(int sem_id)
{
    if(semctl(sem_id,0,IPC_RMID)<0)
    {
        perror("semctl");
    }
    return 0;
}

int init_sem_set(int sem_id,int which,int val)
{
    union semun _un;
    _un.val = val;
    if(semctl(sem_id,which,SETVAL,_un)<0)
    {
        perror("semctl");
        return -1;
    }
}
static int comm_op(int sem_id,int num,int op)
{
    struct sembuf _sembuf;
    _sembuf.sem_num = num;
    _sembuf.sem_op = op;
    _sembuf.sem_flg = 0;

    if(semop(sem_id,&_sembuf,1)<0)
    {
        perror("semop");
        return -1;
    }
    return 0;
}

int P(int sem_id,int num)
{    
    int op = -1;
    return comm_op(sem_id,num,op);
}

int    V(int sem_id,int num)
{
    int op = -1;
    return comm_op(sem_id,num,op);
}

test_sem.c

#include
#include
#include
#include

#define _PATH_NAME_ "/tmp"
#define _PROJ_ID_ 0x6666

int create_sem_set();

union semun
{
    int val;
    struct semid_ds* buf;
    unsigned short *array;
    struct eminfo*_buf;
};

int init_sem_set(int sem_id,int which,int val);
int create_sem_set(int nums);
int get_sem_set();

int destory_sem_set(int sem_id);

int P(int sem_id,int num);

int    V(int sem_id,int num);
[lh@localhost SEM]$ ^C
[lh@localhost SEM]$ cat comm.c
#include"comm.h"

static int comm_sem_set(int nums,int flags)
{
    key_t _key = ftok(_PATH_NAME_,_PROJ_ID_);

    if(_key<0)
    {
        perror("ftok");
        return -1;
    }
//    int sem_id = semget(_key,nums,IPC_CREAT |IPC_EXCL);
    int sem_id = semget(_key,nums,flags);
    if(sem_id <0)
    {
        perror("semget");
        return -2;
    }
    return sem_id;
}

int create_sem_set(int nums)
{
    int flags = IPC_CREAT | IPC_EXCL | 0666;
    return comm_sem_set(nums,flags);
    
}

int get_sem_set()
{
    
    int flags = IPC_CREAT;
    return comm_sem_set(0,flags);
}

int destory_sem_set(int sem_id)
{
    if(semctl(sem_id,0,IPC_RMID)<0)
    {
        perror("semctl");
    }
    return 0;
}

int init_sem_set(int sem_id,int which,int val)
{
    union semun _un;
    _un.val = val;
    if(semctl(sem_id,which,SETVAL,_un)<0)
    {
        perror("semctl");
        return -1;
    }
}
static int comm_op(int sem_id,int num,int op)
{
    struct sembuf _sembuf;
    _sembuf.sem_num = num;
    _sembuf.sem_op = op;
    _sembuf.sem_flg = 0;

    if(semop(sem_id,&_sembuf,1)<0)
    {
        perror("semop");
        return -1;
    }
    return 0;
}

int P(int sem_id,int num)
{    
    int op = -1;
    return comm_op(sem_id,num,op);
}

int    V(int sem_id,int num)
{
    int op = -1;
    return comm_op(sem_id,num,op);
}
[lh@localhost SEM]$ ^C
[lh@localhost SEM]$ clear

[lh@localhost SEM]$ cat test_sem.c
#include"comm.h"
#include
int main()
{
    int sem_id = create_sem_set(1);
    pid_t id = fork();
    init_sem_set(sem_id,0,1);

    if(id ==0)
    {
        int sem_id_child = get_sem_set();
        while(1)
        {
            P(sem_id_child,0);
            printf("A");
            fflush(stdout);
            usleep(rand()%3);
            printf("A");
            fflush(stdout);
            usleep(rand()%12345);
            V(sem_id_child,0);
        }
    }
    else
    {
        while(1)
        {
            P(sem_id,0);
            printf("B");
            fflush(stdout);
            usleep(rand()%3);
            printf("B");
            fflush(stdout);
            usleep(rand()%12234);
            V(sem_id,0);
        }
        wait(NULL);
        destory_sem_set(sem_id);
    }

    return 0;    
}

信号量(semaphore)

另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。


当前标题:信号量(semaphore)-创新互联
标题网址:http://ybzwz.com/article/dchehd.html