• Linux信号量详解


    1.什么是信号量
    信号量是一种特殊的变量,访问具有原子性。
    只允许对它进行两个操作:
    1)等待信号量
    当信号量值为0时,程序等待;当信号量值大于0时,信号量减1,程序继续运行。
    2)发送信号量
    将信号量值加1。

    我们使用信号量,来解决进程或线程间共享资源引发的同步问题。

    2.Linux中信号量的使用
    Linux提供了一组信号量API,声明在头文件sys/sem.h中。
    1)semget函数:新建信号量

    int semget(key_t key,int num_sems,int sem_flags);

    key:信号量键值,可以理解为信号量的唯一性标记。
    num_sems:信号量的数目,一般为1
    sem_flags:有两个值,IPC_CREATE和IPC_EXCL,
    IPC_CREATE表示若信号量已存在,返回该信号量标识符。
    IPC_EXCL表示若信号量已存在,返回错误。

    返回值:相应的信号量标识符,失败返回-1

    2)semop函数:修改信号量的值

    int semop(int sem_id,struct sembuf *sem_opa,size_t num_sem_ops);

    sem_id:信号量标识符
    sem_opa:结构如下

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

    3)semctl函数:用于信号量的初始化和删除

    int semctl(int sem_id,int sem_num,int command,[union semun sem_union]);

    command:有两个值SETVAL,IPC_RMID,分别表示初始化和删除信号量。
    sem_union:可选参数,结构如下:

    union semun{  
        int val; 
        struct semid_ds *buf;  
        unsigned short *arry;  
    }; 

    一般用到的是val,表示要传给信号量的初始值。

    3.Linux信号量使用示例
    下例中,我们写了一个程序,程序中有一个char类型的字符,char message='x'
    然后同时运行这个程序的两个实例。
    第一个实例,带一个参数,将参数的第一个字符赋给message,比如为'0'
    第二个实例,使用默认message值'x'
    我们的目的是,使用信号量,循环执行这两个实例,
    我们可以看到执行结果应该是'x0x0x0x0x0x0'

    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/sem.h>
    union semun
    {
        int val;
        struct semid_ds *buf;
        unsigned short *array;
    };
    int sem_id;
    int set_semvalue()
    {
        union semun sem_union;    
        sem_union.val = 1;
        if(semctl(sem_id,0,SETVAL,sem_union)==-1)
            return 0;
        return 1;
    }
    int semaphore_p()
    {
        struct sembuf sem_b;
        sem_b.sem_num = 0;
        sem_b.sem_op = -1;
        sem_b.sem_flg = SEM_UNDO;
        if(semop(sem_id,&sem_b,1)==-1)
        {
            fprintf(stderr,"semaphore_p failed
    ");
            return 0;
        }
        return 1;
    }
    int semaphore_v()
    {
        struct sembuf sem_b;
        sem_b.sem_num = 0;
        sem_b.sem_op = 1;
        sem_b.sem_flg = SEM_UNDO;
        if(semop(sem_id,&sem_b,1)==-1)
        {
            fprintf(stderr,"semaphore_v failed
    ");
            return 0;
        }
        return 1;
    }
    void del_semvalue()
    {
        //删除信号量
        union semun sem_union;
        if(semctl(sem_id,0,IPC_RMID,sem_union)==-1)
            fprintf(stderr,"Failed to delete semaphore
    ");
    }
    int main(int argc,char *argv[])
    {
        char message = 'x';
        //创建信号量
         sem_id = semget((key_t)1234,1,0666|IPC_CREAT);
        if(argc>1)
        {
            //初始化信号量
            if(!set_semvalue())
            {
                fprintf(stderr,"init failed
    ");
                exit(EXIT_FAILURE);
            }
            //参数的第一个字符赋给message
            message = argv[1][0];
        }
        int i=0;
        for(i=0;i<5;i++)
        {
            //等待信号量
            if(!semaphore_p())
                exit(EXIT_FAILURE);
            printf("%c",message);
            fflush(stdout);
            sleep(1);
            //发送信号量
            if(!semaphore_v())
                exit(EXIT_FAILURE);
            sleep(1);
        }
        printf("
    %d-finished
    ",getpid());
        if(argc>1)
        {
            //退出前删除信号量
            del_semvalue();
        }
        exit(EXIT_SUCCESS);
    }

    输出结果:

  • 相关阅读:
    x-ua-compatible的实践
    在iframe中使用cookie需要注意
    border在IE6设置transparent无效
    开发过程中的一点领悟(2)
    mouseover和mouseout、mouseenter和mouseleave
    scrollWidth的巧妙运用
    后一个div无法遮挡住前一个有img的div
    ie6并不是不支持!important
    window.parent
    (转)nmake学习笔记
  • 原文地址:https://www.cnblogs.com/shijingjing07/p/5615084.html
Copyright © 2020-2023  润新知