信号灯/量

信号灯/信号量(semaphore)

信号量代表某一类资源,其值系统表示系统中该资源的数量

信号量是一个受保护的变量,只能通过三种操作来访问

初始化

P操作(申请资源)

V操作(释放资源)

概念:是不同进程间或一个给定进程内部不同线程间同步的机制。类似我们的PV操作概念:

生产者和消费者场景

P(S)含义如下:

        if(信号量的值大于0) {

                申请资源的任务继续运行;

                信号量的值减一;

                } else {

                        申请资源的任务阻塞;

                }

V(S)含义如下:

        信号量的值加一;

        if (有任务在等待资源) {

                唤醒等待的任务,让其继续运行

        }

三种信号灯

Posix有名信号灯

Posix无名信号灯(linux只支持线程同步)

System V信号灯

Posix有名信号灯和无名信号灯使用:

有名信号灯

有名信号灯打开:

sem_t *sem_open(const char *name, int oflag);

sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);

参数:

name:name是给信号灯起的名字

oflag:打开方式,常用O_CREAT

mode:文件权限。常用0666

value:信号量值。二元信号灯值为1,普通表示资源数目

信号灯文件位置:/dev/shm

有名信号灯关闭

int sem_close(sem_t *sem);

有名信号灯的删除

int sem_unlink(const char* name);

无名信号灯

无名信号灯初始化

int sem_init(sem_t *sem, int shared, unsigned int value);

参数:

sem:需要初始化的信号灯变量

shared: shared指定为0,表示信号量只能由初始化这个信号量的进程使用,不能在进程间使用,linux不支持进程间同步。

Value:信号量的值

无名信号灯销毁int sem_destroy(sem_t* sem);

示例:

#include<stdio.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<semaphore.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<signal.h>
#include<pthread.h>

sem_t sem_w,sem_r;
char* shmaddr;

void destorysem(int sig){
    sem_destroy(&sem_w);
    sem_destroy(&sem_r);
    exit(0);
}

void* readmem(void* arg){
    while(1){
        sem_wait(&sem_r);
        printf("%s\n",shmaddr);
        sem_post(&sem_w);
    }
}
int main(int argc, const char *argv[])
{

    key_t key;
    int shmid;
    struct sigaction act;
    act.sa_handler=destorysem;
    act.sa_flags=0;
    sigemptyset(&act.sa_mask);

    sigaction(SIGINT,&act,NULL);
    key=ftok(".",100);
    if(key<0){
        perror("ftok");
        return -1;
    }

    shmid=shmget(key,500,0666|IPC_CREAT);
    if(shmid<0){
        perror("shmget");
        return -1;
    }

    shmaddr=shmat(shmid,NULL,0);

    sem_init(&sem_r,0,0);
    sem_init(&sem_w,0,1);

    pthread_t tid;
    pthread_create(&tid,NULL,readmem,NULL);

    while(1){
        sem_wait(&sem_w);
        printf(">");
        fgets(shmaddr,500,stdin);
        sem_post(&sem_r);

    }
    return 0;
}
 

PV操作

信号灯P操作

int sem_wait(sem_t *sem);

获取资源,如果信号量为0,表示这时没有相应资源空闲,那么调用线程就将挂起,直到有空闲资源可以获取

信号灯V操作

int sem_post(sem_t *sem);

释放资源,如果没有线程阻塞在该sem上,表示没有线程等待该资源,这时该函数就对信号量的值进行增1操作,表示同类资源多增加了一个。如果至少有一个线程阻塞在该sem上,表示有线程等待资源,信号量为0,这时该函数保持信号量为0不变,并使某个阻塞在该sem上的线程从sem_wait函数中返回

注意:编译posix信号灯需要加pthread动态库。

System V信号灯

System V信号灯使用:

int semget(key_t key, int nsems, int semflg);

功能:创建/打开信号灯

参数:key:ftok产生的key值(和信号灯关联的key值)

        nsems:信号灯集中包含的信号灯数目

        semflg:信号灯集的访问权限,通常为IPC_CREAT |0666

返回值:成功:信号灯集ID;失败:-1

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

功能:对信号灯集合中的信号量进行P - V操作

参数:semid:信号灯集ID

        struct sembuf {

                short sem_num; //要操作的信号灯的编号

                short sem_op;// 1 :释放资源,V操作

                                        // -1 :分配资源,P操作

                short sem_flg;// 0(阻塞),IPC_NOWAIT, SEM_UNDO

        };//对某一个信号灯的操作,如果同时对多个操作,则需要定义这种结构体数组

        nops:要操作的信号灯的个数,1个

返回值:成功:0;失败:-1

int semctl ( int semid, int semnum, int cmd…/*union semun arg*/);

功能:信号灯集合的控制(初始化/删除)

参数:semid:信号灯集IDsemnum:要操作的集合中的信号灯编号

           cmd:

                GETVAL:获取信号灯的值,返回值是获得值

                SETVAL:设置信号灯的值,需要用到第四个参数:共用体

                IPC_RMID:从系统中删除信号灯集合

返回值:成功0;失败-1

  • 16
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值