条件变量

3 POSIX 多任务及同步机制-拓展实验 条件变量与生产者-消费者问题

夙愿已清 提交于 2020-02-02 01:11:46
3 POSIX 多任务及同步机制-拓展实验 条件变量与生产者-消费者问题 一.实验目的 ·理解进程、线程同步问题。 ·掌握POSIX条件变量机制的使用方法。 ·深入理解在动态并发环境下,进程、线程在运行过程中的资源竞争应发的问题,如虚假唤醒 二.实验背景 ·Recall: 进程的同步与互斥 同步问题 互斥问题 ·互斥:一组并发进程中的一个或多个程序段,因共享某一公有资源而导致它们必须以一个不允许交叉执行的单位执行。 ·同步(狭义):异步环境下的一组并发进程,因直接制约而互相发送消息而进行相互合作、互相等待,使得各进程按一定的速度执行的过程称为进程间的同步 ·要解决线程之间的狭义同步问题,有如下两种思路。 ·一种是使用轮询方法,也就是俗称的“忙等待”。就是等待条件满足的线程不断的去查询条件是否得到满足;这种方法实现较为简单,但是会有一定的性能消耗。如果轮询的间隔时间太短,由于上下文的切换就会消耗较多资源;而间隔时间太长则不能及时地响应。 ·另外一种方法就是当条件不满足时,等待该条件的线程就会休眠;当条件满足时系统会唤醒等待该条件的线程,也被称为消息通知机制。 ·条件变量的声明、初始化和销毁 声明:以变量方式声明 P.203, 初始化和销毁函数 ·条件变量的使用: 等待:与一个互斥锁结合使用, pthread_cond_wait 唤醒: pthread_cond_signal 三

Linux c 条件变量cond的使用记录

蹲街弑〆低调 提交于 2020-01-31 03:16:45
  条件变量是实现线程间同步的一种方法,条件变量用来自动阻塞一个线程,直到收到收到一个cond信号或其它特殊情况发送,条件变量使用的时候必须与互斥量同时使用,这是为了保证条件量在线程间操作的“原子性”。 1、创建一个条件变量cond: int pthread_cond_init(pthread_cond_t * cond , const pthread_condattr_t * attr ); 在初始化一个条件变量时如果attr为 NULL,测使用默认值初始化一个条件变量cond,相当于下面的方式定义一个条件变量cond; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 2、销毁一个条件变量cond: int pthread_cond_destroy(pthread_cond_t * cond ); 可以销毁一个条件变量cond,使其未初始化。一个被引用的条件变量是不可被销毁的,使用一个被销毁的条件变量将造成为止的后果,在默认条件下测试,将导致线程将直处于阻塞状态。 3、等待一个条件变量: int pthread_cond_timedwait(pthread_cond_t * cond ,pthread_mutex_t * mutex , const struct timespec *restrict abstime ); int

多线程编程-----线程同步

不问归期 提交于 2020-01-29 15:47:16
  同步,永远是多线程编程中最核心和最重要的话题.同步相关的概念比如:临界区,原子操作,以及互斥量等等   总的来说,在多个线程之间采取同步措施,无非是为了让他们更好的协同工作或者维持共享数据的一致性.   1.共享数据的一致性:   多线程程序多以共享数据作为在线程之间传递数据的手段,由于一个进程所拥有的相当一部分虚拟内存地址都可以被该线程中的所有线程所共享.因此这些被共享的数据大多也已内存空间作为载体.   实际上,保证共享数据一致性的最简单且最好的方法,就是使得该数据成为一个常量,但是如果把一个计数器做成常量是不现实的,一个可以被多个线程访问和改变的计数器只能被看作是一个变量.我要需要通过额外的手段来保证被多个线程共享的变量的一致性.这才有了临界区这个概念.临界区是只能被串行化的访问或执行的某个资源或某段代码.因而临界区也被称作为串行区域.保证临界区有效的最佳方式是利用同步机制,在针对多线程程序的同步机制中包含了很多同步方法,包括原子操作和互斥量,也包括条件变量.   2.互斥量:   在同一时刻,只允许一个线程处于临界区之内的约束被称为互斥(mutex),每一个线程在进入临界区之前都必须先锁定某个对象,只有成功锁定对象的线程才会被允许进入临界区之内,否则会被阻塞,这个对象被称为互斥对象或互斥量.   互斥量有两种状态:已锁定状态和未锁定状态.互斥量每次只能被锁定一次

【Java并发基础】管程简介

只谈情不闲聊 提交于 2020-01-28 21:08:50
前言 在Java 1.5之前,Java语言提供的唯一并发语言就是管程,Java 1.5之后提供的SDK并发包也是以管程为基础的。除了Java之外,C/C++、C#等高级语言也都是支持管程的。 那么什么是管程呢? 见名知意,是指管理共享变量以及对共享变量操作的过程,让它们支持并发。翻译成Java领域的语言,就是管理类的状态变量,让这个类是线程安全的。 synchronized关键字和wait()、notify()、notifyAll()这三个方法是Java中实现管程技术的组成部分。记得学习操作系统时,在线程一块还有信号量机制,管程在功能上和信号量及PV操作类似,属于一种进程同步互斥工具。Java选择管程来实现并发主要还是因为实现管程比较容易。 管程对应的英文是Monitor,直译为“监视器”,而操作系统领域一般翻译为“管程”。 在管程的发展史上,先后出现过三种不同的管程模型,分别是Hasen模型、Hoare模型和MESA模型。现在正在广泛使用的是MESA模型。下面我们便介绍MESA模型。 MESA模型 管程中引入了条件变量的概念,而且每个条件变量都对应有一个等待队列。条件变量和等待队列的作用是解决线程之间的同步问题。 我们来看一个例子来理解这个模型。多个线程对一个共享队列进行操作。 假设线程T1要执行出队操作,但是这个操作要执行成功的前提是队列不能为空

C多线程编程---条件变量

丶灬走出姿态 提交于 2020-01-27 12:09:37
文章目录 1、原理 2、头文件 3、 函数库 3.1、初始化 3.2、pthread_cond_signal 3.3、pthread_cond_broadcast 3.4、pthread_cond_wait 3.5、pthread_cond_timedwait 3.6、pthread_cond_destroy 3.7、操作步骤: 3.8、举例 1、原理 假设我们需要解决这样一个问题:一个列表记录需要处理的任务。一个线程往此列表添加任务,一个线程processTask处理此列表中的任务。这个问题的一个关键点在于processTask怎么判断任务列表不为空。一般有两种方法: 一. processTask线程不断查询任务列表是否为空。 二. 当列表不为空的时候,通知processTask处理相关任务。 第一种方法往往是在一个while循环中判断列表是否为空,如果为空则睡眠一段时间,如果不为空那么把任务取出来并加以处理。此方案需要一个睡眠时间的平衡点如果睡眠时间太长,任务得不到及时的处理,降低效率。如果睡眠时间过短占用CPU资源,却什么都不做,浪费CPU做其它事情的时间。 第二种方法就比较靠谱了,只有当列表不为空的时候才占用CPU的时间,其它时间什么都不做除了睡觉(线程挂起)。此方案就是我们所说的条件变量(condition variable)。 一般条件变量(condition

std::future如何实现

瘦欲@ 提交于 2020-01-26 13:00:48
文章目录 引言 猜测 源码分析 结论 引言 C++11中引入了一个异步编程的利器 std::future (虽然javaGDK5中就已经引入了),这显然使我们的异步编程的过程变得即简介又易维护,但学习不能仅停留在知道它是干什么的的阶段,显然正确的使用时机也是我们需要学习的,但是总感觉对其使用有点不得心应手,遂决定简单的看看源码,看看其是如何实现的. 猜测 在看源码之前 首先自己想一想这个过程当然也是极好的 那我们一起来捋一捋吧 其实过程想来简单 就是在线程结束时以一种方式异步通知当前持有std::future的唯一线程(std::future支持移动不支持复制), 怎么做呢,我当时的想法是这样的 1. 条件变量 future对象中设置一个条件变量 在异步线程结束时调用notify_one(),在get()函数中调用wait(),这样可以实现一个简单的异步调用,缺点是需要互斥量,条件变量,一个仅发生一次的过程这样不免有些浪费,wait()操作更是需要加锁解锁,也就是说这样一个完整的过程我们需要加锁解锁各两次,还需要一个notify_one(),但优点也很明显,过程简单,且如果等待时间较长,可以把cpu让给其他工作线程,全局上节省的时间随等待时间加长而变长,但等待时间短的话除了完成功能就没有丝毫优势了. 2. 自旋锁 自旋锁显然也可以解决这个问题,我们只需要设置一个类内的原子变量

【杂谈】再看生产-消费模式

喜夏-厌秋 提交于 2020-01-26 10:11:50
生产者和消费者之间为什么隔着一个队列? 首先,生产者与消费者由于速度的不一致,所以需要一个空间用于缓冲。这可以将生产者与消费者解耦,生产者产出数据的时候,不需要把数据交到消费者手上才行,只要把数据丢入缓冲区就好。这样就可以各做各的。 为什么缓冲区是一个队列? 通常情况下,这个缓冲区的数据结构是一个有序的队列。实际上如果对处理顺序没啥要求,其实也不一定要用队列。插空都可以。 为什么访问的缓冲区的时候要获得锁? 缓冲区这个数据结构会被多线程并发访问(生产者、消费者线程),所以需要加锁,一方面保护它的结构不被破坏,另一方面保证代码的正确性。 这样是不是就可以用了? 是,用是可以用了,但是性能可能会比较差。 为什么性能会比较差? 考虑这样一个场景:缓冲区已满。生产者会一直尝试往里面丢东西,所以就一直"获得锁-释放锁-获得锁-释放锁"。一方面,生产者空转,浪费CPU时间片,就会影响其他线程的调度。这时候如果有一个消费者处理完手头的数据,想再拿一个出来处理,那这时候生产者和消费者就会进行不必要的竞争,因为这个时候生产者抢到了锁也没用。 这,这可如何是好啊? 简单,分两种情况,一种是当缓冲区满的时候,如果生产者再尝试往里面丢东西,就把它挂起。同理,当缓冲区为空的时候,如果消费者再尝试往里面,也把它挂起。 那什么时候唤醒呢? 不是一样的吗,当缓冲区来数据的时候(从无到有),就唤醒消费者线程

Linux多线程与同步

守給你的承諾、 提交于 2020-01-15 08:02:25
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢! 典型的UNIX系统都支持一个进程创建多个线程(thread)。在 Linux进程基础 中提到,Linux以进程为单位组织操作,Linux中的线程也都基于进程。尽管实现方式有异于其它的UNIX系统,但Linux的多线程在逻辑和使用上与真正的多线程并没有差别。 多线程 我们先来看一下什么是多线程。在 Linux从程序到进程 中,我们看到了一个程序在内存中的表示。这个程序的整个运行过程中,只有一个控制权的存在。当函数被调用的时候,该函数获得控制权,成为激活(active)函数,然后运行该函数中的指令。与此同时,其它的函数处于离场状态,并不运行。如下图所示: Linux从程序到进程 我们看到,各个方块之间由箭头连接。各个函数就像是连在一根线上一样,计算机像一条流水线一样执行各个函数中定义的操作。这样的一个程序叫做单线程程序。 多线程就是允许一个进程内存在多个控制权,以便让多个函数同时处于激活状态,从而让多个函数的操作同时运行。即使是单CPU的计算机,也可以通过不停地在不同线程的指令间切换,从而造成多线程同时运行的效果。如下图所示,就是一个多线程的流程: main()到func3()再到main()构成一个线程,此外func1()和func2()构成另外两个线程

linux多线程同步

大憨熊 提交于 2020-01-14 00:21:31
1. 互斥量 是线程同步的一种机制,用来保护多线程的共享资源。同一时刻,只允许一个线程对临界区进行访问。互斥量的工作流程:创建一个互斥量,把这个互斥量的加锁调用放在临界区的开始位置,解锁调用放到临界区的结束位置。当内核优先把某个线程调度到临界区的开始位置时,线程执行这个加锁调用,并进入临界区对资源进行操作。此时其他线程再被内核调度到这里的时候,由于该互斥量已被加锁状态,得不到锁会一直阻塞在这里,导致其他线程不能进入临界区,直到刚刚那个进入临界区的线程离开临界区并执行解锁调用。 2. 条件变量 与互斥量不同,互斥量是防止多线程同时访问共享的互斥变量来保护临界区。条件变量是多线程间可以通过它来告知其他线程某个状态发生了改变,让等待在这个条件变量的线程继续执行。通俗一点来讲:设置一个条件变量让线程1等待在一个临界区的前面,当其他线程给这个变量执行通知操作时,线程1才会被唤醒,继续向下执行。 3. 读写锁 与互斥量的功能类似,对临界区的共享资源进行保护!互斥量一次只让一个线程进入临界区,读写锁比它有更高的并行性。读写锁有以下特点: 如果一个线程用读锁锁定了临界区,那么其他线程也可以用读锁来进入临界区,这样就可以多个线程并行操作。但这个时候,如果再进行写锁加锁就会发生阻塞,写锁请求阻塞后,后面如果继续有读锁来请求,这些后来的读锁都会被阻塞!这样避免了读锁长期占用资源,防止写锁饥饿

[Linux]多线程

十年热恋 提交于 2020-01-08 23:01:14
得于斯者, 毁于斯 文章目录 1. Linux下线程概念 2. 线程控制 2.1 线程创建 2.2 线程终止 2.3 线程等待 2.4 线程分离 3. 线程安全 3.1 线程安全的实现 3.2 实现互斥 3.3 实现同步 3.3.1 条件变量实现同步 3.3.2 信号量POSIX实现同步 4. 线程池 操作系统线程概念: https://blog.csdn.net/new_bee_01/article/details/103868668 1. Linux下线程概念 2. 线程控制 POSIX线程库 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的 要使用这些函数库,要通过引入头文<pthread.h> 链接这些线程函数库时要使用编译器命令的“-lpthread”选项 2.1 线程创建 tid作用 代码示例 create.c # include <stdio.h> # include <unistd.h> # include <stdlib.h> # include <pthread.h> void * thread_start ( void * arg ) { while ( 1 ) { printf ( "线程:%s\n" , ( char * ) arg ) ; sleep ( 1 ) ; } return NULL ; } int