UNIX网络编程:IPC之信号量

信号量: 主要用来控制多个进程对临界资源的互斥访问,进程通过信号量来判断是否有可以访问的资源,信号量是一种同步机制

信号是一种处理异步事件的方法; 不同于信号量

信号量是一个计数器可用于同步多进程对共享数据对象的访问;

要获得共享资源,进程需要:(1)测试控制该资源的信号量;
(2)若此信号量值为正, 则进程可以使用该资源,进程将信号量值减一,表示进程使用了一个资源单位;
(3)若此信号量值为0, 则进程进入睡眠状态,直至信号量值大于0,当进程被唤醒后,又开始执行(1);

当进程不再使用由一个信号量控制的共享资源时,该信号量的值加一,如果i有进程正在睡眠以等待此信号量,则唤醒他们,为了正确的实现信号量,信号量的测试以及减一操作必须是原子操作,所以,信号量通常在内核实现

信号量的三个操作导致信号量使用的复杂性:
(1)信号量并非一个负值,必须将信号量定义为含有一个或多个信号量值的集合,当创建一个信号量时,要指定该集合中的各个值;
(2)创建信号量和对其赋初值分开是一个弱点,因不能原子的创建一个信号量集合,并且对该集合中的所有值赋初值;
(3)即使没有进程使用,信号量依然存在,因此必须考虑在进程终止时有没有释放信号量

信号量的操作函数
ftok

key_t ftok(char *pathname, char proj);
成功返回与路径相对应的一个健值,具有唯一性;失败返回-1;

semget

int semget (key_t key, int nsems , int semflg)
创建一个信号量集或访问一个已存在的信号量集;成功返回信号量的ID,失败返回-1;
key是由ftok产生的键值;
nsems是创建的信号量的个数;
semflg是设置信号量的访问权限标志;

semop

int semop (int semid, struct sembuf *spos, int nspos)
对信号量进行操作,用于改变信号量的键值;成功返回0, 失败返回-1;
semid是信号量集的标志符;
spos指向结构体数组的指针,表明要进行的操作
nspos表明数组的元素个数

Struct sembuf (/usr/include/sys$ vi sem.h)
{
Unsigned short sem_num; /*sem index in array*/
  Short sem_op; /* sem operation */
  Short sem_flg;/* operation flags */ sem_flg&IPC_RND 0
};

其中,如果sem_op大于0,那么操作值加入到信号量的值中,并唤醒等待信号增加的进程,如果sem_op为0,当信号量的值是0的时候,函数返回,否则阻塞直到信号量的值为0,如果sem_op小于0,函数判断信号量的值加上这个负值,如果结果为0唤醒等待信号量为0的进程,如果小于0函数阻塞,如果大于0,那么从信号量里面减去这个值并返回。

semctl

int semctl (int semid, int semnum, int cmd, union semun arg)
信号量的控制函数;
semid要操作的信号量标志符;
cmd是操作的命令;IPC_RMID, SETVAL,GETVAL等
arg联合体的结构如下:
Union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
void *__pad;
}

以下是对这几个函数的测试:

//semcreate
#include "utility.h"

int main(int ac, char **av)
{
    key_t key_id;
    key_id = ftok(av[1], 0xFF);

    if(key_id == -1){
        printf("ftok error.\n");
        exit(1);
    }

    int sem_id = semget(key_id, 1, IPC_CREAT|IPC_EXCL|0666);
    if(sem_id == -1){
        printf("semget error.\n");
        exit(1);
    }

    printf("create sem ok, sem_id = %d\n", sem_id);
    return 0;
}


//semsetvalue:
#include "utility.h"

union semun
{
    int    val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *__buf;
    void *__pad;
};

int main(int ac, char **av)
{
    key_t key_id;
    key_id = ftok(av[1], 0xFF);

    int sem_id = semget(key_id, 0, 0);

    union semun init;
    init.val = atoi(av[2]);
    int sem = semctl(sem_id, 0, SETVAL, init);

    if(sem == -1){
        printf("sem set value fail.\n");
        exit(1);
    }
    printf("sem set value ok\n");

    return 0;
}



//semgetvalue
#include "utility.h"

int main(int ac, char **av)
{
    key_t key_id = ftok(av[1], 0xFF);
    int sem_id = semget(key_id, 0, 0);
    int sem = semctl(sem_id, 0, GETVAL);
    printf("sem get value = %d\n", sem);

    return 0;
}



//semrmid 删除信号量
#include "utility.h"

int main(int ac, char **av)
{
    key_t key_id;
    key_id = ftok(av[1], 0xFF);
    int sem_id = semget(key_id, 0, 0);
    semctl(sem_id, 0, IPC_RMID);
    return 0;
}


//semopin 信号量的v操作
#include "utility.h"


int main(int ac, char **av)
{
    key_t key_id = ftok(av[1], 0xFF);
    int sem_id = semget(key_id, 0, 0);

    struct sembuf v;
    v.sem_num = 0;
    v.sem_op = 2;
    v.sem_flg = 0;

    int res = semop(sem_id, &v, 1);
    if(res == -1){
        printf("operator sem error.\n");
        exit(1);
    }
    printf("operator ok.\n");
    return 0;
}


//seopde 信号量的p操作
#include "utility.h"


int main(int ac, char **av)
{
    key_t key_id = ftok(av[1], 0xFF);
    int sem_id = semget(key_id, 0, 0);

    struct sembuf p;
    p.sem_num = 0;
    p.sem_op = -1;
    p.sem_flg = 0;

    int res = semop(sem_id, &p, 1);
    if(res == -1){
        printf("operator sem error.\n");
        exit(1);
    }
    printf("operator ok.\n");
    return 0;
}

//头文件
#pragma once

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



using namespace std;

makefile文件

all:semcreate semrmid semsetvalue semgetvalue semopin semopde

semcreate:semcreate.cpp
    g++ semcreate.cpp -o semcreate

semrmid:semrmid.cpp
    g++ semrmid.cpp -o semrmid

semsetvalue:semsetvalue.cpp
    g++ semsetvalue.cpp -o semsetvalue

semgetvalue:semgetvalue.cpp
    g++ semgetvalue.cpp -o semgetvalue

semopin:semopin.cpp
    g++ semopin.cpp -o semopin

semopde:semopde.cpp
    g++ semopde.cpp -o semopde

.PHONY:clean

clean:
    rm semcreate semrmid semsetvalue semgetvalue semopin semopde

你可能感兴趣的:(网络编程,ipc,信号量,semget,semctl-op)