在多线程或者多进程编程中,有一个非常需要关注的东西,那就是同步以及互斥问题。

  同步是指多个进程之间的协作,而互斥是指多个进程之间,为了争夺有限的资源,而进行的竞争。

  理论很高端,但经过自己几天的学习,发现操作系统中,线程的信号量还是比较简单易懂的……

  ————————————————————————————————————————

  信号量是用来解决线程间同步或互斥的一种机制,也是一个特殊的变量,变量的值代表着当前可以利用的资源。

  如果等于0,那就意味着现在没有资源可用。

  根据信号量的值可以将信号量分为二值信号量和计数信号量:

  (计数信号量)就像一间公共厕所,里面一共有十个坑(最大是32767),算是十个资源。在同一时间可以容纳十个人,当满员的时候,外面的人必须等待里面的人出来,释放一个资源,然后才能在进一个,当他进去之后,厕所又满员了,外面的人还得继续等待……

  (二值信号量)就像自己家的卫生间,一般只有一个马桶,在同一时间只能有一个人来用。

  信号量只能进程两个原子操作,P操作和V操作,

  概念:

  原子操作,就是不能被更高等级中断抢夺优先的操作。

  由于操作系统大部分时间处于开中断状态,所以,一个程序在执行的时候可能被优先级更高的线程中断。

  而有些操作是不能被中断的,不然会出现无法还原的后果,这时候,这些操作就需要原子操作。就是不能被中断的操作。

  P操作:如果有可用的资源(信号量>0),那么占用一个资源(信号量-1)。如果没有可用的资源(信号量=0),则进程被阻塞,直到系统重新给他分配资源。

  V操作:如果在该信号量的等待队列中有进程在等待该资源,则唤醒一个进程,否则释放一个资源(信号量+1)

  

  POSIX提供两种信号量,有名信号量无名信号量,有名信号量一般是用在进程间同步,无名信号量一般用在线程间同步。

  两种信号量的操作流程,大概有下面的几点不同:

  

  主要在于两种信号量初始化和销毁的方式不同。

  对了,还有一点是非常需要注意的,和在操作共享内存时需要连接库一样,在编译信号量的时候,也需要加上-pthread参数

  ————————————————————————————————————————————————————————————

  首先先来学习有名信号量

  创建有名信号量:

  创建或者打开一个信号量,需要使用sem_open()函数,函数原形如下:

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

  返回值sem_t 是一个结构,如果函数调用成功,则返回指向这个结构的指针,里面装着当前信号量的资源数。

  参数name,就是信号量的名字,两个不同的进程通过同一个名字来进行信号量的传递。

  参数oflag,当他是O_CREAT时,如果name给出的信号量不存在,那么创建,此时必须给出mode和vaule。当他是O_EXCL时,好像没有啥太重要的意义。

  参数mode,很好理解,用来指定信号量的权限。

  参数vaule,则是信号量的初始值。

  关闭有名信号量:

  关闭有名信号量所使用的函数是sem_close(sem_t *sem)

  这个函数只有一个参数,意义也非常明显,就是指信号量的名字。

  

  信号量操作:

  前面已经说过,在使用信号量时,有两个非常重要的操作

  P操作:使用的函数是sem_wait(sem_t *sem)

  如果信号量的值大于零,sem_wait函数将信号量减一,并且立即返回。如果信号量的值小于零,那么该进程会被阻塞在原地。

  V操作:使用的函数是sem_post(sem_t *sem)

  当一个进程使用完某个信号量时,他应该调用sem_post函数来告诉系统收回资源。

  sem_post函数和sem_wait函数的功能刚好相反,他会把指定的信号量加一

  删除有名信号量:

  当使用完有名信号后,需要调用函数sem_unlink来释放资源。

  函数原形:int sem_unlink(const char *name)

  ——————————————————————————————————————————————————————————

  实战演练!!!!

  需求:创建两个进程,A进程打印A,然后等待B进程打印B,在B进程打印完了后,A进程在打印C。

  A进程代码如下:

  

#include<stdio.h>
#include<stdlib.h>
#include<semaphore.h>
#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h> #define SEM_NAME "name" int main()
{
sem_t *sem_test; sem_test = sem_open("ni", O_CREAT, , );
if(sem_test < )
{
printf("A进程创建信号量失败!errno=%d\n",errno);
exit(-);
} printf("进程A进入等待……\n");
printf("A\n");
sem_wait(sem_test);
printf("C\n");
sem_post(sem_test);
printf("A进程执行完毕!\n");

   sem_close(sem_test);
   sem_unlink("ni");

    return 0;
}

  B进程代码如下:

  

#include<stdio.h>
#include<stdlib.h>
#include<semaphore.h>
#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h> #define SEM_NAME "name" int main()
{
sem_t *sem_test; sem_test = sem_open("ni",); if(sem_test < )
{
printf("B进程创建信号量失败!errno=%d\n",errno);
exit(-);
} printf("B\n");
sem_post(sem_test);
printf("B进程执行完毕!\n");
sem_close(sem_test);
sem_unlink("ni");
return ;
}

  现在进程编译(一定要记得在编译选项后加上-pthread哦!!)

   

  代码执行结果!!

   

  执行得很成功!!

  值得一提的是,如果在执行中出现了段错误 (核心已转储)这种错误信息的话,最好是去/dev/shm/下看一下,看看是否有个黄色的文件,权限被设置的奇高!

  我就遇到了这样的问题。

  哎!虽然整篇文章就这么短短的几十行,但我可是足足奋斗了将近五个小时才搞懂!!

  明天~继续加油!!

  

       

  

  

  

  

  

  

Linux学习笔记(15)-信号量的更多相关文章

  1. Linux学习笔记26——信号量

    一 信号量的基本概念 信号量:它是一个特殊变量,只允许对它进行等待和发送信号这两种操作. 假设有一个信号量变量sv P(sv):用于等待,如果sv的值大于零,就给它减去1,如果它的值等于零,就挂起该进 ...

  2. Linux学习笔记15——GDB 命令详细解释【转】

    GDB 命令详细解释 Linux中包含有一个很有用的调试工具--gdb(GNU Debuger),它可以用来调试C和C++程序,功能不亚于Windows下的许多图形界面的调试工具. 和所有常用的调试工 ...

  3. Linux学习笔记15—RPM包的安装OR源码包的安装

    RPM安装命令1. 安装一个rpm包rpm –ivh 包名“-i” : 安装的意思“-v” : 可视化“-h” : 显示安装进度另外在安装一个rpm包时常用的附带参数有:--force : 强制安装, ...

  4. Linux学习笔记15-YUM安装

    rpm软件包缺点:需要手工解决软件包的依赖关系.使用YUM可解决该问题. YUM(Yellodog Updater, Modified)是一个RPM前端程序,主要目的是设计用来自动解决RPM的依赖关系 ...

  5. Linux 学习笔记

    Linux学习笔记 请切换web视图查看,表格比较大,方法:视图>>web板式视图 博客园不能粘贴图片吗 http://wenku.baidu.com/view/bda1c3067fd53 ...

  6. deepin linux学习笔记(四)进不去图形界面怎么办?

    目录 deepin linux学习笔记(四)进不去图形界面怎么办? 前言 更换成lxde桌面 进不去图形界面怎么办? 总结 deepin linux学习笔记(四)进不去图形界面怎么办? 前言 生命不息 ...

  7. Linux 学习笔记之超详细基础linux命令 Part 13

    Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 12---------------- ...

  8. Linux 学习笔记之超详细基础linux命令 Part 9

    Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 8----------------- ...

  9. Linux 学习笔记之超详细基础linux命令 Part 8

    Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 7----------------- ...

  10. Linux 学习笔记之超详细基础linux命令 Part 3

    Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 2----------------- ...

随机推荐

  1. jQuery动画slideUp()不正常位移原因

    用jQuery写一个列表.当点击底部按钮时,列表中序号超过6的项目可以向下拉出或者向上收起. 用slideUp(),遇见一个问题.展开列表项会产生不正常位移,如下图所示.动画结束发生位移. 出现这个问 ...

  2. jpeg huffman coding table

    亮度DC系数的取值范围及序号:                                                               序号(size) 取值范围 0 0  1 - ...

  3. Eclipse常用快捷键汇总

    经常使用eclipse进行开发,不掌握快捷键步行啊,在此整理了一些快捷键,大家要灵活运用啊... (注:红色标出来的是经常使用到的快捷键,磨刀不误砍柴工啊...) Ctrl+1 快速修复(最经典的快捷 ...

  4. axios基本用法

    vue更新到2.0之后,作者就宣告不再对vue-resource更新,而是推荐的axios,前一段时间用了一下,现在说一下它的基本用法. 首先就是引入axios,如果你使用es6,只需要安装axios ...

  5. 数据结构-浙大 MOOC 笔记一 基本概念

    做一些笔记记录自己的学习过程 第一节课介绍了数据结构的基本概念,首先没有直接给出相关的定义而是通过思考如何在书架上摆放书籍这样一个简单的类比了解到数据的组织方式的重要性,并通过printN函数的循环实 ...

  6. 学习 opencv---(8)非线性滤波:中值滤波,双边滤波

    正如我们上一篇文章中讲到的,线性滤波可以实现很多种不同的图像变换.然而非线性滤波,如中值滤波器和双边滤波器,有时可以达到更好的实现效果. 邻域算子的其他一些例子还有对 二值图像进行操作的形态学算子,用 ...

  7. qlikview 扩展插件制作教程-EchartsGeoMap

    效果图   显示效果和echarts官方demo一样,运行速度尚可. 第一次写博客,排版很渣以后慢慢改进. 基础知识 以EchartsGeoMap为例,讲一下怎么制作一个基础的QlikView Ext ...

  8. 全排列算法的JS实现

    问题描述:给定一个字符串,输出该字符串所有排列的可能.如输入“abc”,输出“abc,acb,bca,bac,cab,cba”. 虽然原理很简单,然而我还是折腾了好一会才实现这个算法……这里主要记录的 ...

  9. ubuntu 搞坏了sudoers文件之修复方案

    pkexec visudo askubuntu原回答摘抄如下 On a modern Ubuntu system (and many other GNU/Linux distributions), f ...

  10. nginx负载SignalR

    前几天写了篇聊天室服务器扩展随想,今天有空开始实施第一步, 聊天服务器用SignalR self-host,负载用nginx,当然这只是测试,实际使用可能还需要修改. 第一步,搭好SignalR服务, ...