zoukankan      html  css  js  c++  java
  • UNIX环境高级编程——system V信号量

    1. 信号量(semaphore)主要用于保护临界资源。
    进程可以根据它判断是否能访问某些共享资源。
    信号量除了用于访问控制外,还可用于进程同步,也就是进程间通信。

    2. 信号量分类:
    a. 二值信号量: 信号量的值只能取0或1,类似于互斥锁mutex,但两者又不同:

    mutex 与 二值信号量的区别:
    信号量强调共享资源,只要共享资源可用,其他进程同样可以修改信号量的值;
    互斥锁更强调进程,占用资源的进程使用完资源后,必须由进程本身来接锁。

    b. 计数信号量:信号量的值可以取任意非负值。

    system V信号量通过定义如下概念给信号量增加了另外一级复杂度。

    计数信号量集:一个或多个信号量(构成一个集合),其中每个都是计数信号量。每个集合的信号量数存在一个限制,一般在25个数量级。


    3.semget函数(信号量的创建

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

    #include <sys/sem.h>
    int senget(key_t key,int nsems,int oflag);

    nsems参数指定集合中的信号量数。如果我们不创建一个新的信号量集,而只是访问一个已存在的集合,那就可以把该参数指定为0。一旦创建完一个信号量集,我们就不能改变其中的信号量数。

        oflag值是SEM_R和SEM_A常值得组合。他们还可以与IPC _CREAT或IPC_CREAT | IPC_EXCL按位或。

        当实际操作为创建一个新的信号量集时,相应的semid_ds结构的以下成员将被初始化。

    (1)sem_perm结构的uid和cuid成员被置为调用进程的有效用户ID,gid和cgid成员被置为调用进程的有效组ID。

    (2)oflag参数中的读写权限位存入sem_perm.mode。

    (3)sem_otime被置为0,sem_ctime则被置为当前时间。

    (4)sem_nsems被置为nsems参数的值。

    (5)与该集合中每个信号量关联的各个sem结构并不初始化。这些结构时在以SET_VAL或SETALL命令调用semctl时初始化的。


    4.semop函数(操作信号量

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

    #include <sys/sem.h>
    int semop(int semid,struct sembuf *opsptr,size_t nops);
      其中opsptr指向一个如下结构的数组:

     struct sembuf{
               unsigned short sem_num;  /* semaphore number */
               short          sem_op;   /* semaphore operation */
               short          sem_flg;  /* operation flags */
    };


    假定有一个信号量变量sv,

    P(sv):用于等待,如果sv大于0,就给它减去1,如果它的值等于0,就挂起该进程的执行

    V(sv):用于发送信号,如果有其他进程因等待sv而挂起,就让它恢复运行,如果没有进程因等待sv而被挂起,就给它加1


    semaphore sv=1;

    loop forever{

    P(sv);

    critical code section;

    V(sv);

    noncritical code section;

    }


    信号量函数定义如下所示:

    #include<sys/sem.h>

    int semctl(int sem_id, int sem_num, int command, ...);//用来直接控制信号量信息

    int semget(key_t key, int num_sems, int sem_flags);//创建一个新信号量或取得一个已有信号量的键

    int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);//用于改变信号量的值


    /* After the #includes, the function prototypes and the global variable, we come to the
     main function. There the semaphore is created with a call to semget, which returns the
     semaphore ID. If the program is the first to be called (i.e. it's called with a parameter
     and argc > 1), a call is made to set_semvalue to initialize the semaphore and op_char is
     set to X. */
    
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    #include <sys/sem.h>
    
    #include "semun.h"
    
    static int set_semvalue(void);
    static void del_semvalue(void);
    static int semaphore_p(void);
    static int semaphore_v(void);
    
    static int sem_id;
    
    
    int main(int argc, char *argv[])
    {
        int i;
        int pause_time;
        char op_char = 'O';
    
        srand((unsigned int)getpid());
    
        sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT);
    
        if (argc > 1) {
            if (!set_semvalue()) {
                fprintf(stderr, "Failed to initialize semaphore
    ");
                exit(EXIT_FAILURE);
            }
            op_char = 'X';
            sleep(2);
        }
    
    /* Then we have a loop which enters and leaves the critical section ten times.
     There, we first make a call to semaphore_p which sets the semaphore to wait, as
     this program is about to enter the critical section. */
    
        for(i = 0; i < 10; i++) {
    
     if (!semaphore_p()) exit(EXIT_FAILURE);
            printf("%c", op_char);fflush(stdout);
            pause_time = rand() % 3;
            sleep(pause_time);
            printf("%c", op_char);fflush(stdout);
    
    /* After the critical section, we call semaphore_v, setting the semaphore available,
     before going through the for loop again after a random wait. After the loop, the call
     to del_semvalue is made to clean up the code. */
    
            if (!semaphore_v()) exit(EXIT_FAILURE);
    
            pause_time = rand() % 2;
            sleep(pause_time);
        }
    
        printf("
    %d - finished
    ", getpid());
    
        if (argc > 1) {
            sleep(10);
            del_semvalue();
        }
    
        exit(EXIT_SUCCESS);
    }
    
    /* The function set_semvalue initializes the semaphore using the SETVAL command in a
     semctl call. We need to do this before we can use the semaphore. */
    
    static int set_semvalue(void)
    {
        union semun sem_union;
    
        sem_union.val = 1;
        if (semctl(sem_id, 0, SETVAL, sem_union) == -1) return(0);
        return(1);
    }
    
    /* The del_semvalue function has almost the same form, except the call to semctl uses
     the command IPC_RMID to remove the semaphore's ID. */
    
    static void del_semvalue(void)
    {
        union semun sem_union;
    
    if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
            fprintf(stderr, "Failed to delete semaphore
    ");
    }
    
    /* semaphore_p changes the semaphore by -1 (waiting). */
    
    static int semaphore_p(void)
    {
        struct sembuf sem_b;
    
        sem_b.sem_num = 0;
        sem_b.sem_op = -1; /* P() */
        sem_b.sem_flg = SEM_UNDO;
        if (semop(sem_id, &sem_b, 1) == -1) {
            fprintf(stderr, "semaphore_p failed
    ");
            return(0);
        }
        return(1);
    }
    
    /* semaphore_v is similar except for setting the sem_op part of the sembuf structure to 1,
     so that the semaphore becomes available. */
    
    static int semaphore_v(void)
    {
        struct sembuf sem_b;
    
        sem_b.sem_num = 0;
        sem_b.sem_op = 1; /* V() */
        sem_b.sem_flg = SEM_UNDO;
        if (semop(sem_id, &sem_b, 1) == -1) {
            fprintf(stderr, "semaphore_v failed
    ");
            return(0);
        }
        return(1);
    }




  • 相关阅读:
    js动态生成按钮,页面用DIV简单布局
    Maven初学之经验浅谈
    pl/sql注册码
    windows server 2012R2 网络慢的那些事
    sql 优化
    巧用selectKey
    list集合,map集合遍历
    oracle中declare程序块用法
    处理oracle锁表
    关于img标签图片不加载不识别相对路径得解决办法
  • 原文地址:https://www.cnblogs.com/wangfengju/p/6172740.html
Copyright © 2011-2022 走看看