信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在semtake的时候,就阻塞在哪里)。而互斥锁是用在多线程多任务互斥的,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程unlock,其他的线程才开始可以利用这个资源。比如对全局变量的访问,有时要加锁,操作完了,在解锁。有的时候锁和信号量会同时使用的”

也就是说,信号量不一定是锁定某一个资源,而是流程上的概念,比如:有A,B两个线程,B线程要等A线程完成某一任务以后再进行自己下面的步骤,这个任务并不一定是锁定某一资源,还可以是进行一些计算或者数据处理之类。而线程互斥量则是“锁住某一资源”的概念,在锁定期间内,其他线程无法对被保护的数据进行操作。在有些情况下两者可以互换。 
两者之间的区别:

  作用域 上锁时
信号量 进程间或线程间(linux仅线程间) 只要信号量的value大于0,其他线程就可以sem_wait成功,成功后信号量的value减一。若value值不大于0,则sem_wait阻塞,直到sem_post释放后value值加一
互斥锁 线程间 只要被锁住,其他任何线程都不可以访问被保护的资源 
成功后否则就阻塞

以下是信号灯(量)的一些概念: 
信号灯与互斥锁和条件变量的主要不同在于”灯”的概念,灯亮则意味着资源可用,灯灭则意味着不可用。如果说后两中同步方式侧重于”等待”操作,即资源不可用的话,信号灯机制则侧重于点灯,即告知资源可用;没有等待线程的解锁或激发条件都是没有意义的,而没有等待灯亮的线程的点灯操作则有效,且能保持灯亮状态。当然,这样的操作原语也意味着更多的开销。 
信号灯的应用除了灯亮/灯灭这种二元灯以外,也可以采用大于1的灯数,以表示资源数大于1,这时可以称之为多元灯。 
1. 创建和 注销 
POSIX信号灯标准定义了有名信号灯和无名信号灯两种,但LinuxThreads的实现仅有无名灯,同时有名灯除了总是可用于多进程之间以外,在使用上与无名灯并没有很大的区别,因此下面仅就无名灯进行讨论。 
int sem_init(sem_t *sem, int pshared, unsigned int value) 
这是创建信号灯的API,其中value为信号灯的初值,pshared表示是否为多进程共享而不仅仅是用于一个进程。LinuxThreads没有实现多进程共享信号灯,因此所有非0值的pshared输入都将使sem_init()返回-1,且置errno为ENOSYS。初始化好的信号灯由sem变量表征,用于以下点灯、灭灯操作。 
int sem_destroy(sem_t * sem) 
被注销的信号灯sem要求已没有线程在等待该信号灯,否则返回-1,且置errno为EBUSY。除此之外,LinuxThreads的信号灯 注销函数不做其他动作。 
2. 点灯和灭灯 
int sem_post(sem_t * sem) 
点灯操作将信号灯值原子地加1,表示增加一个可访问的资源。 
int sem_wait(sem_t * sem) 
int sem_trywait(sem_t * sem) 
sem_wait()为等待灯亮操作,等待灯亮(信号灯值大于0),然后将信号灯原子地减1,并返回。sem_trywait()为sem_wait()的非阻塞版,如果信号灯计数大于0,则原子地减1并返回0,否则立即返回-1,errno置为EAGAIN。 
3. 获取灯值 
int sem_getvalue(sem_t * sem, int * sval) 
读取sem中的灯计数,存于*sval中,并返回0。 
4. 其他 
sem_wait()被实现为取消点,而且在支持原子”比较且交换”指令的体系结构上,sem_post()是唯一能用于异步信号处理函数的POSIX异步信号 安全的API。 
----------------------------

线程同步:何时互斥锁不够,还需要条件变量?

假设有共享的资源sum,与之相关联的mutex 是lock_s.假设每个线程对sum的操作很简单的,与sum的状态无关,比如只是sum++.那么只用mutex足够了.程序员只要确保每个线程操作前,取得lock,然后sum++,再unlock即可.每个线程的代码将像这样

add() 
{  
    pthread_mutex_lock(lock_s); 
    sum++; 
    pthread_mutex_unlock(lock_s); 
}

如果操作比较复杂,假设线程t0,t1,t2的操作是sum++,而线程t3则是在sum到达100的时候,打印出一条信息,并对sum清零. 这种情况下,如果只用mutex, 则t3需要一个循环,每个循环里先取得lock_s,然后检查sum的状态,如果sum>=100,则打印并清零,然后unlock.如果sum& amp; amp; amp; lt;100,则unlock,并sleep()本线程合适的一段时间. 
这个时候,t0,t1,t2的代码不变,t3的代码如下

print()
{  while(1)  {  pthread_mutex_lock(lock_s);  if(sum>=100)  {  printf(“sum reach 100!”);  pthread_mutex_unlock(lock_s);  }  else{  pthread_mutex_unlock(lock_s);  my_thread_sleep(100);  return OK;  }  }
}

这种办法有两个问题 
1) sum在大多数情况下不会到达100,那么对t3的代码来说,大多数情况下,走的是else分支,只是lock和unlock,然后sleep().这浪费了CPU处理时间. 
2) 为了节省CPU处理时间,t3会在探测到sum没到达100的时候sleep()一段时间.这样却又带来另外一个问题,亦即t3响应速度下降.可能在sum到达200的时候,t3才会醒过来. 
3) 这样,程序员在设置sleep()时间的时候陷入两难境地,设置得太短了节省不了资源,太长了又降低响应速度.真是难办啊!

这个时候,condition variable内裤外穿,从天而降,拯救了焦头烂额的你.

你首先定义一个condition variable. 
    pthread_cond_t cond_sum_ready=PTHREAD_COND_INITIALIZER; 
t0,t1,t2的代码只要后面加两行,像这样

add()
{ pthread_mutex_lock(lock_s); sum++; pthread_mutex_unlock(lock_s); if(sum>=100) pthread_cond_signal(&cond_sum_ready);
} 
而t3的代码则是
print
{ pthread_mutex_lock(lock_s); while(sum<100) pthread_cond_wait(&cond_sum_ready, &lock_s); printf(“sum is over 100!”); sum=0; pthread_mutex_unlock(lock_s); returnOK;
} 
注意两点: 1) 在thread_cond_wait()之前,必须先lock相关联的mutex, 因为假如目标条件未满足,pthread_cond_wait()实际上会unlock该mutex, 然后block,在目标条件满足后再重新lock该mutex, 然后返回. 2) 为什么是while(sum<100),而不是if(sum<100) ?这是因为在pthread_cond_signal()和pthread_cond_wait()返回之间,有时间差,假设在这个时间差内,还有另外一个线程t4又把sum减少到100以下了,那么t3在pthread_cond_wait()返回之后,显然应该再检查一遍sum的大小.这就是用 while的用意 

信号量 互斥锁 条件变量的区别相关推荐

  1. 信号量 互斥量 条件变量

    原文:https://blog.csdn.net/qq_32646795/article/details/78221005 本文打算写一些和锁有关的东西,谈一谈我对锁的原理和实现的理解,主要包含以下方 ...

  2. 关于互斥锁,条件变量的内核源码解析

    一.解决问题和适用范围 主要是用来等待一个条件,这个条件可能需要另一个线程来满足这个条件.这个和我们平常适用的pthread_mutex_lock的最大不同在于后者保护的一般是一个代码段(也就是关键区 ...

  3. 信号量与条件变量的区别

    注意信号量与条件变量的区别 信号量内容可见:http://www.cnblogs.com/charlesblc/p/6142868.html 信号量.共享内存,以及消息队列等System V IPC三 ...

  4. 信号量和条件变量的区别

    互斥锁与信号量的异同 当信号量的初值为1,且在0和1之间变化时,成为二元信号量.其与互斥锁的区别在于:互斥锁有拥有者这一概念,信号量则没有.互斥锁由同一线程加放锁,信号量可以由不同线程进行PV操作. ...

  5. linux 信号量锁 内核,Linux内核信号量互斥锁应用

    主要介绍了Linux 内核关于信号量,互斥锁等的应用 内核同步机制-信号量/互斥锁/读-写信号量 sema ,mutex ,rwsem 信号量 通用信号量 用户类进程之间使用信号量(semaphore ...

  6. Linux系统编程---17(条件变量及其函数,生产者消费者条件变量模型,生产者与消费者模型(线程安全队列),条件变量优点,信号量及其主要函数,信号量与条件变量的区别,)

    条件变量 条件变量本身不是锁!但它也可以造成线程阻塞.通常与互斥锁配合使用.给多线程提供一个会合的场所. 主要应用函数: pthread_cond_init 函数 pthread_cond_destr ...

  7. java 信号量 互斥锁_线程同步(互斥锁与信号量的作用与区别)

    "信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在semtake的时候,就阻塞在 哪里).而互斥锁是用在多线程多任务互斥的,一 ...

  8. 二值信号量和互斥锁到底有什么区别?

    原文链接:https://www.cnblogs.com/codescrew/p/8970514.html 在说明之前我先抛出结论:互斥锁和二值信号量在使用上非常相似,但是互斥锁解决了优先级翻转的问题 ...

  9. 互斥锁机制,互斥锁与读写锁区别

    Linux的4种锁机制: 互斥锁:mutex,用于保证在任何时刻,都只能有一个线程访问该对象.当获取锁操作失败时,线程会进入睡眠,等待锁释放时被唤醒 读写锁:rwlock,分为读锁和写锁.处于读操作时 ...

最新文章

  1. 面试题整理10 最小的k个数
  2. 聚焦 | 阿里灵杰AI工程化峰会来了
  3. 在Java、C#和C++中遍历集合
  4. 使用SAP Analytics Cloud显示新冠肺炎病毒感染人数的实时信息
  5. 上海应用技术学院c语言实验报告9,上海工程技术大学C语言实验报告
  6. AIgorand的基本原理
  7. vb上传文件到MySQL_ASP.NET上传文件到数据库VB版
  8. synchronized()_JMM(四):浅谈synchronized锁
  9. python selenium 文件上传_python-selenium -- 文件上传操作
  10. 微信小程序——获取具体地理位置信息
  11. 调用iphone客户端进行授权发微博的方法--使用友盟组件
  12. ios开发中如何隐藏各种bar
  13. 图文教程使用一套键鼠控制两台电脑
  14. 易语言大漠插件模块制作后台找字FindStrExS和FindStrFastExS
  15. React脚手架创建项目
  16. 围棋棋手、电影、境界层次
  17. FilterSecurityInterceptor详解
  18. 利用 Python 特性在 Jinja2 模板中执行任意代码
  19. adcclk最大_DSP28335 ADC程序 中文说明 -
  20. idea 亮度 调整_如何设置显示屏幕的亮度

热门文章

  1. 编辑器未包含main类型_Shopify模版编辑器问题排查及解决办法汇总
  2. 目录下文件过多无法删除
  3. STM8单片机串口同时识别自定义协议和Modbus协议
  4. LettCode50. Pow(x, n)
  5. Linux中安装开源JDK(windows的JDK只能安装半开源)
  6. 【github】git 使用命令大全
  7. apt报错Hash 校验和不符解决办法
  8. ubuntu配置spyder和jupyter notebook的工作目录
  9. 阿里天池供应链需求预测比赛小结
  10. 用Java搭建一套访问redis的API