在windows中使用信号量已经在另一篇文章中讲过了,信号量的详细细节也已经展示了,本文介绍如何在linux环境下使用c语言编写信号量类型的例子代码。
windows c语言使用信号量

与windows环境下不同,在linux下,头文件unistd.h或者pthread.h都没有直接包含P,V操作,也就是wait(),signal(),也即信号量的P,V操作需要自行编程实现。信号量结构体(参考上面链接)已经清楚,但是这还不够,实现信号量需要满足以下两个条件:
1.信号量操作只能是原子操作
2.除了P,V操作外,其他函数无法操作信号量

我们先看Linux下C语言提供的相关函数:

1.pthread_t;
2.pthread_mutex_t;
3.pthread_cond_t;
4.pthread_mutex_lock();
5.pthread_mutex_unlock();
6.pthread_cond_wait();
7.pthread_cond_signal();
8.pthread_mutex_init();
9.pthread_cond_init();

1-3为相关变量定义,4、5为互斥访问的锁操作,6、7为条件变量,8、9为初始化函数。
函数具体用法可以使用命令查看:

man pthread_cond_wait
#或者
man function

锁操作可以实现互斥访问,条件变量可以实现进程同步功能,因此这些函数可以组成信号量操作,函数具体内容就不再赘述。
首先定义信号量结构体:

typedef struct
{int value;pthread_mutex_t mutex;//信号量为原子操作pthread_cond_t cond;
}sema_t;

value表示资源量,mutex实现原子操作,cond实现阻塞等待以及唤醒。
P操作即首先占用一个资源量,如果不够则阻塞,资源够用立即返回:

void sema_wait(sema_t *sema)
{pthread_mutex_lock(&sema->mutex);sema->value--;while(sema->value<0)pthread_cond_wait(&sema->cond,&sema->mutex);pthread_mutex_unlock(&sema->mutex);}

V操作首先释放一个资源量,并调唤醒一个条件变量,这里不用判断有没有被阻塞的进程,条件变量cond已经帮你实现了:

void sema_signal(sema_t *sema)
{pthread_mutex_lock(&sema->mutex);sema->value++;pthread_cond_signal(&sema->cond);pthread_mutex_unlock(&sema->mutex);
}

这样就完整实现了P,V操作。
下面看一个使用信号量的例子:

  • 系统中有3个线程:生产者、计算者、消费者
  • 系统中有2个容量为4的缓冲区:buffer1、buffer2
  • 生产者
    • 生产’a’、‘b’、‘c’、‘d’、‘e’、‘f’、‘g’、'h’八个字符
    • 放入到buffer1
    • 打印生产的字符
  • 计算者
    • 从buffer1取出字符
    • 将小写字符转换为大写字符,按照 input:OUTPUT 的格式打印
    • 放入到buffer2
  • 消费者
    • 从buffer2取出字符
    • 打印取出的字符
  • 程序输出结果(实际输出结果是交织的)

很明显,需要五个信号量:

sema_t mutex1,mutex2;//互斥访问缓冲区
sema_t wait_empty_buff1;
sema_t wait_full_buff1;
sema_t wait_empty_buff2;
sema_t wait_full_buff2;

produce线程负责向buffer1中写数据,有几个要求:
1.buff1互斥访问
2.缓冲区满不能写
3.写完通知缓冲区满

void *produce()
{int item;for(int i=0;i<item_count;i++){sema_wait (&wait_empty_buff1);sema_wait (&mutex1);item='a'+i;put_item(1,item);printf("Produce item: %c\n",item);sema_signal (&mutex1);sema_signal (&wait_full_buff1);}return NULL;
}

consume线程与produce类似,也有如上述三个要求,但是是2、3是相反的并且互斥访问buff2:
1.buff2互斥访问
2.缓冲区空不能拿
3.拿完通知缓冲区空

void *consume()
{int item;for(int i=0;i<item_count;i++){sema_wait (&wait_full_buff2);sema_wait (&mutex2);item=get_item(2);printf("Consume item: %c\n",item);sema_signal (&mutex2);sema_signal (&wait_empty_buff2);}return NULL;
}

compute比较复杂,是上述两个线程的结合体,代码如下:

void *compute()
{int item,item_res;for(int i=0;i<item_count;i++){sema_wait (&wait_full_buff1);sema_wait (&mutex1);item=get_item(1);sema_signal (&mutex1);sema_signal (&wait_empty_buff1);item_res=item-('a'-'A');printf("Compute item: %c-->%c\n",item,item_res);sema_wait (&wait_empty_buff2);sema_wait (&mutex2);put_item(2,item_res);sema_signal (&mutex2);sema_signal (&wait_full_buff2);}return NULL;
}

由buff1拿出计算后放入buff2,拿的时候buff1不能空,放的时候buff2不能满。
信号量初始化:

mutex1.value=1;//互斥访问,一次只能允许一个
mutex2.value=1;
wait_empty_buff1.value=bsize-1;//缓冲区大小-1
wait_empty_buff2.value=bsize-1;
wait_full_buff1.value=0;//没有写数据时为空
wait_full_buff2.value=0;

至此全部完毕。
题目2:
系统中有2个线程:ping 线程和 pong 线程

  • ping 线程先执行
  • ping 线程执行流程如下
    1. 打印输出 ping
    2. 等待 pong 线程输出
    3. 执行第 1 步
  • pong 线程执行流程如下
    1. 打印输出 pong
    2. 等待 ping 线程输出
    3. 执行第 1 步
  • 程序输出结果
    ping
    pong
    ping
    pong

    想法类似,读者可以自行实现
    全部完整代码地址

C语言使用信号量(Linux)相关推荐

  1. linux sntp 代码,C语言window(linux)平台的SNTP实现

    C语言实现window(linux)平台的SNTP,本程序功能主要是实现电脑(或者设备)时间同步.摘录部分代码: unsigned char liVnMode; /* LeapSecond(2bits ...

  2. 用C语言编写一个Linux下的简单shell程序

    这是一个简单的C程序,展示了如何进行系统调用执行logout cd ls pwd pid rm mkdir mv cp等命令,这是一个简单的命令解释程序shell,其源代码如下: #include & ...

  3. linux环境c语言实现who,C语言编程实现Linux命令——who

    C语言编程实现Linux命令--who 实践分析过程 who命令是查询当前登录的每个用户,它的输出包括用户名.终端类型.登录日期及远程主机,在Linux系统中输入who命令输出如下: 我们先man一下 ...

  4. C语言到嵌入式Linux开发项目指导

    C语言到嵌入式Linux开发项目指导 第一阶段C语言 1.常量与变量,数据类型,数据类型转换,数据输入与输出: 2.C语言运算符,C语言操作符,C语言表达式,表达式优先级: 3.C语言流程控制,分支, ...

  5. linux python开发环境sql数据迁移到mysql_运用Python语言编写获取Linux基本系统信息(三):Python与数据库编程,把获取的信息存入数据库...

    运用Python语言编写获取Linux基本系统信息(三):Python与数据库编程 有关前两篇的链接: 一.实验环境: Python2.7.10.pycharm.VM虚拟机.CentOS6.3.mys ...

  6. C语言关键字restrict(linux 中为 “__restrict”)

    C语言关键字restrict(linux 中为 "__restrict") 关键字restrict只可用于指针,表明该指针是访问一个数据对象的惟一且初始的方式. 该关键字的作用是允 ...

  7. linux申请信号量,linux 信号量

    https://www.jianshu.com/p/6e72ff770244 无名信号量 只适合用于一个进程的不同线程 #include #include #include #include #inc ...

  8. linux mysql c语言编程,在Linux下通过C语言操作MySQL数据库

    2010年1月27日 晚 22:10 作者:longyun(http://www.linuxdiyf.com/mailto:mtd527@gmail.com) 续:小弟最近想学习数据库,并想开发一个简 ...

  9. linux下c语言写文件,Linux下C语言之文件操作

    C语言库函数的文件操作实际上是独立于具体的操作系统平台的,不管是在DOS.Windows.Linux还是在VxWorks中都是这些函数: 创建和打开的函数: FILE *fopen(const cha ...

  10. linux下清理信号量,Linux下kill的信号量列表

    Linux下kill的信号量列表 kill -s SIGSTOP PID i.e. kill -s SIGSTOP PID (暂停进程) kill -s SIGCONT PID (恢复运行进程) #d ...

最新文章

  1. 教你如何以对象的方式思考
  2. ZABBIX3.0配置邮件报警
  3. Java并发编程系列之CyclicBarrier详解
  4. 推荐2个十分好用的pandas数据探索分析神器!
  5. linux framebuffer 例子
  6. 计算机学业水平测试字处理多少分,【计算机应用论文】计算机应用基础学业水平的测试问题(共3624字)...
  7. 长沙计算机类中等职业学校,长沙铁航职业中等技术学校
  8. 《第一行代码》学习笔记12-UI(1)
  9. SQL-基础学习4--聚集函数:AVG(),COUNT(),MAX(),MIN(),SUM();聚集不同值:DISTINCT
  10. 等级保护体系、信息安全管理体系及等级保护管理制度
  11. STC15学习笔记 第一章 流水灯与数码管
  12. Python解析XML文档
  13. python基础教程四级查数据_四六级成绩还可以这样查?Python助你装B一步到位!!!...
  14. Google Android Market电子市场/应用商店
  15. 华为手机日历倒计时_华为手机日历日程提醒不响怎么解决?
  16. Oracle审计与数据库防火墙(AVDF)介绍
  17. Apple Music预告登场 暗示AirPod 3新款耳机发售?
  18. RabbitMQ消息100%不丢失?
  19. 全景拍摄不推荐使用全景相机的背后原因
  20. Jenkins自动构建(CI/DI)项目(一)

热门文章

  1. 解决tomcat内存溢出问题
  2. 酷派android升级失败,酷派大神X7刷机失败变砖开不了机 救砖教程
  3. C语言编程齿轮轮廓线坐标,C语言程序实现齿轮基本参数几何尺寸计算
  4. 高频量化交之李:在华尔街狼舞岁
  5. Kaggle Tabular Playground Series - Jan 2022 学习笔记2(使用时间序列的线性回归)
  6. vivo android 刷机教程,vivo刷机步骤盘点【图文教程】
  7. 京瓷2211打印机清零_打印机墨粉盒清零的方法
  8. java如何逆向工程_总结一下java如何进行逆向工程
  9. 水系图一般在哪里找得到_虹吸雨水排水系统相较于传统重力排水有哪些优点?...
  10. 汇总3种获取水系数据的途径