System V信号量(1)

信号量和P、V原语由Dijkstra(迪杰斯特拉)提出
信号量
互斥:P、V在同一个进程中
同步:P、V在不同进程中
信号量值含义
S>0:S表示可用资源的个数
S=0:表示无可用资源,无等待进程
S<0:|S|表示等待队列中进程个数

信号量
struct semaphore
{
int value;
pointer_PCB queue;
}

P 原语
P(s)
{
s.value = s.value--;
if (s.value < 0)
{
该进程状态置为等待状状态
将该进程的PCB插入相应的等待队列s.queue末尾
}
}

V 原语
V(s)
{
s.value = s.value++;
if (s.value < =0)
{
唤醒相应等待队列s.queue中等待的一个进程
改变其状态为就绪态
并将其插入就绪队列
}
}

信号量集结构
struct semid_ds {
struct ipc_perm sem_perm;  /* Ownership and permissions */
time_t      sem_otime; /* Last semop time */
time_t      sem_ctime; /* Last change time */
unsigned short  sem_nsems; /* No. of semaphores in set */
};

信号量集函数
#include
#include
#include

int semget(key_t key, int nsems, int semflg);
int semctl(int semid, int semnum, int cmd, ...);
int semop(int semid, struct sembuf *sops, unsigned nsops);

semget 函数
功能:用来创建和访问一个信号量集
原型
int semget(key_t key, int nsems, int semflg);
参数
key: 信号集的名字
nsems:信号集中信号量的个数
semflg: 由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值:成功返回一个非负整数,即该信号集的标识码;失败返回-1

shmctl 函数
功能:用于控制信号量集
原型
int semctl(int semid, int semnum, int cmd, ...);
参数
semid:由semget返回的信号集标识码
semnum:信号集中信号量的序号
cmd:将要采取的动作(有三个可取值)
最后一个参数根据命令不同而不同
返回值:成功返回0;失败返回-1

命令
说明
SETVAL
设置信号量集中的信号量的计数值
GETVAL
获取信号量集中的信号量的计数值
IPC_STAT
把semid_ds结构中的数据设置为信号集的当前关联值
IPC_SET
在进程有足够权限的前提下,把信号集的当前关联值设置为semid_ds数据结构中给出的值
IPC_RMID
删除信号集

semop 函数
功能:用来创建和访问一个信号量集
原型
int semop(int semid, struct sembuf *sops, unsigned nsops);
参数
semid:是该信号量的标识码,也就是semget函数的返回值
sops:是个指向一个结构数值的指针
nsops:信号量的个数
返回值:成功返回0;失败返回-1

sembuf结构体:
struct sembuf {
short sem_num;
short sem_op;
short sem_flg;
};
sem_num是信号量的编号。
sem_op是信号量一次PV操作时加减的数值,一般只会用到两个值,一个是“-1”,也就是P操作,等待信号量变得可用;另一个是“+1”,也就是我们的V操作,发出信号量已经变得可用
sem_flag的两个取值是IPC_NOWAIT或SEM_UNDO

sem.c
#include
#include
#include
#include
#include
#include
#include
#include


#include
#include
#include
#include




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
                                    (Linux-specific) */
};


#define ERR_EXIT(m) \
        do \
        { \
                perror(m); \
                exit(EXIT_FAILURE); \
        } while(0)


int sem_create(key_t key)
{
int semid;
semid = semget(key, 1, IPC_CREAT | IPC_EXCL | 0666);
if (semid == -1)
ERR_EXIT("semget");


return semid;
}


int sem_open(key_t key)
{
int semid;
semid = semget(key, 0, 0);
if (semid == -1)
ERR_EXIT("semget");


return semid;
}


int sem_setval(int semid, int val)
{
union semun su;
su.val = val;
int ret;
ret = semctl(semid, 0, SETVAL, su);
if (ret == -1)
ERR_EXIT("sem_setval");


return 0;
}


int sem_getval(int semid)
{
        int ret;
        ret = semctl(semid, 0, GETVAL, 0);
        if (ret == -1)
                ERR_EXIT("sem_getval");


        return ret;
}


int sem_d(int semid)
{
int ret;
ret = semctl(semid, 0, IPC_RMID, 0);
if (ret == -1)
ERR_EXIT("semctl");


return 0;
}


int sem_p(int semid)
{
struct sembuf sb = {0, -1, 0};
int ret;
ret = semop(semid, &sb, 1);
if (ret == -1)
ERR_EXIT("semop");


return ret;
}


int sem_v(int semid)
{
        struct sembuf sb = {0, 1, 0};
        int ret;
        ret = semop(semid, &sb, 1);
        if (ret == -1)
                ERR_EXIT("semop");


        return ret;
}


int main(int argc, char *argv[])
{
int semid;
semid = sem_create(1234);
sleep(5);
sem_d(semid);

return 0;
}

semtool.c
#include
#include
#include
#include
#include
#include
#include


#define ERR_EXIT(m) \
        do \
        { \
                perror(m); \
                exit(EXIT_FAILURE); \
        } while(0)


union semun {
int val;                  /* value for SETVAL */
struct semid_ds *buf;     /* buffer for IPC_STAT, IPC_SET */
unsigned short *array;    /* array for GETALL, SETALL */
 /* Linux specific part: */
struct seminfo *__buf;    /* buffer for IPC_INFO */
};


int sem_create(key_t key)
{
int semid = semget(key, 1, 0666 | IPC_CREAT | IPC_EXCL);
if (semid == -1)
ERR_EXIT("semget");


return semid;
}


int sem_open(key_t key)
{
int semid = semget(key, 0, 0);
if (semid == -1)
ERR_EXIT("semget");


return semid;
}


int sem_p(int semid)
{
struct sembuf sb = {0, -1, /*0IPC_NOWAIT*/SEM_UNDO};
int ret = semop(semid, &sb, 1);
if (ret == -1)
ERR_EXIT("semop");


return ret;
}


int sem_v(int semid)
{
struct sembuf sb = {0, 1, /*0*/SEM_UNDO};
int ret = semop(semid, &sb, 1);
if (ret == -1)
ERR_EXIT("semop");


return ret;
}


int sem_d(int semid)
{
int ret = semctl(semid, 0, IPC_RMID, 0);
if (ret == -1)
ERR_EXIT("semctl");
return ret;
}


int sem_setval(int semid, int val)
{
union semun su;
su.val = val;
int ret = semctl(semid, 0, SETVAL, su);
if (ret == -1)
ERR_EXIT("semctl");


printf("value updated...\n");
return ret;
}


int sem_getval(int semid)
{
int ret = semctl(semid, 0, GETVAL, 0);
if (ret == -1)
ERR_EXIT("semctl");


printf("current val is %d\n", ret);
return ret;
}


int sem_getmode(int semid)
{
        union semun su;
        struct semid_ds sem;
        su.buf = &sem;
        int ret = semctl(semid, 0, IPC_STAT, su);
        if (ret == -1)
                ERR_EXIT("semctl");


        printf("current permissions is %o\n",su.buf->sem_perm.mode);
        return ret;
}


int sem_setmode(int semid,char* mode)
{
        union semun su;
        struct semid_ds sem;
        su.buf = &sem;


        int ret = semctl(semid, 0, IPC_STAT, su);
        if (ret == -1)
                ERR_EXIT("semctl");


        printf("current permissions is %o\n",su.buf->sem_perm.mode);
        sscanf(mode, "%o", (unsigned int*)&su.buf->sem_perm.mode);
        ret = semctl(semid, 0, IPC_SET, su);
        if (ret == -1)
                ERR_EXIT("semctl");


        printf("permissions updated...\n");


        return ret;
}


void usage(void)
{
fprintf(stderr, "usage:\n");
fprintf(stderr, "semtool -c\n");
fprintf(stderr, "semtool -d\n");
fprintf(stderr, "semtool -p\n");
fprintf(stderr, "semtool -v\n");
fprintf(stderr, "semtool -s \n");
fprintf(stderr, "semtool -g\n");
fprintf(stderr, "semtool -f\n");
fprintf(stderr, "semtool -m \n");
}


int main(int argc, char *argv[])
{
int opt;


opt = getopt(argc, argv, "cdpvs:gfm:");
if (opt == '?')
exit(EXIT_FAILURE);
if (opt == -1)
{
usage();
exit(EXIT_FAILURE);
}


key_t key = ftok(".", 's');
int semid;
switch (opt)
{
case 'c':
                sem_create(key);
                break;
        case 'p':
                semid = sem_open(key);
                sem_p(semid);
                sem_getval(semid);
                break;
        case 'v':
                semid = sem_open(key);
                sem_v(semid);
sem_getval(semid);
                break;
        case 'd':
                semid = sem_open(key);
                sem_d(semid);
                break;
        case 's':
                semid = sem_open(key);
                sem_setval(semid, atoi(optarg));
                break;
        case 'g':
                semid = sem_open(key);
                sem_getval(semid);
                break;
        case 'f':
                semid = sem_open(key);
                sem_getmode(semid);
                break;
        case 'm':
semid = sem_open(key);
sem_setmode(semid, argv[2]);
break;
}


return 0;
}

makefile:
.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=sem semtool
all:$(BIN)
%.o:%.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f *.o $(BIN)





你可能感兴趣的:(linux网络编程)