Linux网络编程【信号量】

举报
xcc-2022 发表于 2022/10/24 21:03:00 2022/10/24
【摘要】 06. 信号量 6.1 信号量概述信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负的整数计数器,代表公共资源的个数, 它被用来控制对公共资源的访问。比如说我有四台打印机,允许四个线程跑,前面都无法完成,所以就有了信号量;编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量值大于 0 时,则可以访问,否则将阻塞。PV 原语是对信号量的操作,一次 P 操作使信...

06. 信号量

6.1 信号量概述

信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负的整数计数器,代表公共资源的个数, 它被用来控制对公共资源的访问。

比如说我有四台打印机,允许四个线程跑,前面都无法完成,所以就有了信号量;

编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量值大于 0 时,则可以访问,否则将阻塞。

PV 原语是对信号量的操作,一次 P 操作使信号量减1,一次 V 操作使信号量加1。

信号量主要用于进程或线程间的同步和互斥这两种典型情况。

信号量数据类型为:sem_t。

信号量用于互斥:

1528181665768

信号量用于同步:1528181692967

6.2 sem_init函数

初始化信号量:

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:
    创建一个信号量并初始化它的值。一个无名信号量在被使用前必须先初始化。
参数:
    sem:信号量的地址。
    pshared:等于 0,信号量在线程间共享(常用);不等于0,信号量在进程间共享。
    value:信号量的初始值。
返回值:
    成功:0
    失败: - 1

6.3 sem_destroy函数

销毁信号量:

#include <semaphore.h>

int sem_destroy(sem_t *sem);
功能:
    删除 sem 标识的信号量。
参数:
    sem:信号量地址。
返回值:
    成功:0
    失败: - 1

6.4 信号量P操作(减1)

可理解为加锁

#include <semaphore.h>

int sem_wait(sem_t *sem);
功能:
    将信号量的值减 1。操作前,先检查信号量(sem)的值是否为 0,若信号量为 0,此函数会阻塞,直到信号量大于 0 时才进行减 1 操作。
参数:
    sem:信号量的地址。
返回值:
    成功:0
    失败: - 1

int sem_trywait(sem_t *sem);
   以非阻塞的方式来对信号量进行减 1 操作。
   若操作前,信号量的值等于 0,则对信号量的操作失败,函数立即返回。

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
   限时尝试将信号量的值减 1
   abs_timeout:绝对时间

abs_timeout补充说明:

struct timespec {
    time_t tv_sec;      /* seconds */ // 秒
    long   tv_nsec; /* nanosecondes*/ // 纳秒
}

time_t cur = time(NULL);        //获取当前时间。
struct timespec t;              //定义timespec 结构体变量t
t.tv_sec = cur + 1;             // 定时1秒
sem_timedwait(&cond, &t);

6.5 信号量V操作(加1)

可理解为解锁

#include <semaphore.h>

int sem_post(sem_t *sem);
功能:
    将信号量的值加 1 并发出信号唤醒等待线程(sem_wait())。
参数:
    sem:信号量的地址。
返回值:
    成功:0
    失败:-1

6.6 获取信号量的值

#include <semaphore.h>

int sem_getvalue(sem_t *sem, int *sval);
功能:
    获取 sem 标识的信号量的值,保存在 sval 中。
参数:
    sem:信号量地址。
    sval:保存信号量值的地址。
返回值:
    成功:0
    失败:-1

6.7 程序示例

sem_t sem;      //信号量变量

//打印小写字母
void* fun2(void *arg)
{
    char ch =' ';
    //申请资源 将可用资源减1
    sem_wait(&sem);
    for(ch = 'a'; ch<='z';ch++)
    {
        putchar(ch);
        fflush(stdout);
        usleep(10000);//100ms
    }
    //释放资源 将可用资源加1
    sem_post(&sem);

    return NULL;
}

//打印大写字母
void* fun1(void *arg)
{
    char ch =' ';
    //申请资源 将可用资源减1
    sem_wait(&sem);
    for(ch = 'A'; ch<='Z';ch++)
    {
        putchar(ch);
        fflush(stdout);//刷新缓存区
        usleep(10000);//100ms
    }
     putchar('\n');
    //释放资源 将可用资源加1
    sem_post(&sem);
    return NULL;
}
int main()
{

    int ret = -1;
    pthread_t tid1, tid2;

    //初始化一个信号变量
    ret = sem_init(&sem,0,1);
    if(ret != 0)
    {
        printf("sem_init failed...\n");
        return 1;
    }
    printf("初始化一个信号量ok...\n");
    //创建两个线程
    pthread_create(&tid1,NULL,fun1,NULL);
    pthread_create(&tid2,NULL,fun2,NULL);

    //等待两个线程结束
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    //销毁信号量
    sem_destroy(&sem);
    printf("\n main thread exit...\n");

    return 0;
}

xcc@ubuntu:~/9th$ ./a.out
初始化一个信号量ok…
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
main thread exit…

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。