pthread

互斥量和条件变量

a 夏天 提交于 2020-02-13 09:05:33
ps:参考了很多博客,但是当时没记下链接。。。 互斥器和条件变量用法如下: pthread_mutex_lock(&lock); while (condition_is_false) { pthread_cond_wait(&cond, &lock); } 上面那个while能换成if吗?答案是不能,否则会导致spurious wakeup虚假唤醒。因为不仅要在pthread_cond_wait前要检查条件是否成立,在pthread_cond_wait之后也要检查。因为pthread_cond_wait不仅能被pthread_cond_signal/pthread_cond_broadcast唤醒,而且还会被其它信号唤醒,后者就是虚假唤醒。 而且有可能多个线程被同时唤醒。那么在第一个获取完资源后,后面的全都无法获取资源了。 pthread_cond_wait内的互斥量只能保证同步。 linux的 pthread_cond_wait是用futex系统调用,这个是慢速系统调用 ,看过apue知道任何慢速系统调用被信号打断的时候会返回-1,并且把errno置为EINTR,如果慢速系统调用的重启功能被关闭,需要在调用该系统调用的地方手动重启它,像下面这样: while (1) { int ret = syscall(); if (ret < 0 && errno == EINTR)

条件变量与互斥量(2)

て烟熏妆下的殇ゞ 提交于 2020-02-13 03:52:45
因为线程的代码基本没怎么写过,leet-code出了线程题,刷下。 1116. 打印零与奇偶数 假设有这么一个类: class ZeroEvenOdd { public ZeroEvenOdd(int n) { ... } // 构造函数 public void zero(printNumber) { ... } // 仅打印出 0 public void even(printNumber) { ... } // 仅打印出 偶数 public void odd(printNumber) { ... } // 仅打印出 奇数 } 相同的一个 ZeroEvenOdd 类实例将会传递给三个不同的线程: 线程 A 将调用 zero(),它只输出 0 。 线程 B 将调用 even(),它只输出偶数。 线程 C 将调用 odd(),它只输出奇数。 每个线程都有一个 printNumber 方法来输出一个整数。请修改给出的代码以输出整数序列 010203040506... ,其中序列的长度必须为 2n。 示例 1: 输入:n = 2 输出:"0102" 说明:三条线程异步执行,其中一个调用 zero(),另一个线程调用 even(),最后一个线程调用odd()。正确的输出为 "0102"。 示例 2: 输入:n = 5 输出:"0102030405" VERSION 1:   三锁版

RAII手法封装的互斥器mutex和条件变量condition类

坚强是说给别人听的谎言 提交于 2020-02-13 03:45:39
目录 RAII手法封装的互斥器mutex和条件变量condition类 前言 概要 原则 宏定义部分 互斥锁(Mutex) 条件变量(Condition variable) 倒计时(CountDownLatch) 死锁调试 小结 RAII手法封装的互斥器mutex和条件变量condition类 前言 近来在学习陈硕老师的muduo库,阅读了里面RAII手法封装的线程安全互斥锁的源码,期间遇到很多问题,包括有些宏对新手非常不友好等,解决这些问题花了很多时间,结合源码和自己的思考以及查阅的资料,本文记录下相关的 难点 ,如有错误,欢迎指正交流。 概要 首先谈谈什么是 RAII ,用自己的话说RAII的做法是使用一个对象,在其构造时获取资源,在对象生命期控制对资源的访问使之始终保持有效,最后在对象析构的时候释放资源。RAII在C++中应用很广泛,用于管理资源、避免内存泄露。 原则 muduo库遵循以下几个原则: 用RAII手法封装mutex的创建、销毁、加锁、解锁这四个操作。 只用非递归的mutex(即不可重入的mutex) 不手工调用lock()和unlock()函数,一切交给栈上的Guard对象的构造和析构函数负责。 每次构造Guard对象的时候,思考一路上(调用栈上)已经持有的锁,防止因加锁顺序不同而导致死锁(deadlock)。由于Guard对象是栈上对象

Posix信号量

血红的双手。 提交于 2020-02-13 00:02:42
1、概述   信号量(semaphore)是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语。信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有。信号量的值为正的时候,说明它空闲。所测试的线程可以锁定而使用它。若为0,说明它被占用,测试的线程要进入睡眠队列中,等待被唤醒。Posix信号量分为有名信号量和无名信号量(也叫基于内存的信号量)。 2、Posix有名信号量   有名信号量既可以用于线程间的同步也可以用于进程间的同步。 1)由sem_open来创建一个新的信号量或打开一个已存在的信号量。其格式为: sem_t *sem_open(const char *name,int oflag,mode_t mode,unsigned int value); 返回:若成功则为指向信号量的指针,若出错则为SEM_FAILED 其中,第三、四个参数可以没有,主要看第二个参数如何选取。 oflag参数:可以是0、O_CREAT或O_CREAT|O_EXCL。如果指定O_CREAT标志而没有指定O_EXCL,那么只有当所需的信号量尚未存在时才初始化它。但是如果所需的信号量已经存在也不会出错。 但是如果在所需的信号量存在的情况下指定O_CREAT|O_EXCL却会报错。 mode参数:指定权限位。 value参数:指定信号量的初始值

IPC通信:Posix信号灯

假装没事ソ 提交于 2020-02-12 23:23:46
  信号灯用来实现 同步 ——用于多线程,多进程之间同步共享资源(临界资源)。信号灯分两种,一种是有名信号灯,一种是基于内存的信号灯。 有名信号灯 ,是根据外部名字标识,通常指代文件系统中的某个文件。 而基于内存的信号灯 ,它主要是把信号灯放入内存的,基于内存的信号灯,同步多线程时,可以放到该多线程所属进程空间里;如果是同步多进程,那就需要把信号灯放入到共享内存中(方便多个进程访问)。   有名信号灯和基于内存的信号灯,具体区别体现在创建和销毁两个函数。有名信号灯使用sem_open和sem_close函数。基于内存的信号灯使用sem_init和sem_destroy函数。sem_init的参数可以控制是同步多线程,还是多进程;且该函数只能调用1次,因为调用后信号灯就存在了( 内存指针存在)。一般,使用基于内存的信号灯同步同进程多线程,使用有名信号灯同步多进程。 有名信号灯同步多线程: 1 1.sem_open函数。 2 功能:创建并初始化信号灯,如果存在就返回存在的信号灯。 3 头文件:#include <semaphore.h> 4 函数原型:sem_t * sem_open(const char * name,int oflag,mode_t mode,unsigned int value); 5 或者:sem_t * sem_open(const char * name

线程之间共享变量需要注意哪些??

梦想与她 提交于 2020-02-11 22:01:23
线程共享同一个变量是否需要加锁? 那么就根据需要来定。但是如果两个线程有可能同时修改这个变量的话, 那么一定是需要加锁的。 代码中如果没有pthread_join主线程会很快结束从而使整个进程结束,从而使创建的线程没有机会开始执行就结束了。 加入pthread_join后,主线程会一直等待直到等待的线程结束自己才结束,使创建的线程有机会执行。 pthread_join函数及linux线程 pthread_join使一个线程等待另一个线程结束。 代码中如果没有pthread_join主线程会很快结束从而使整个进程结束,从而使创建的线程没有机会开始执行就结束了。 加入pthread_join后,主线程会一直等待直到等待的线程结束自己才结束,使创建的线程有机会执行。 所有线程都有一个线程号,也就是Thread ID。其类型为pthread_t。通过调用pthread_self()函数可以获得自身的线程号。 来源: CSDN 作者: 一个可爱的程序猴 链接: https://blog.csdn.net/blackdevil_/article/details/104268345

深入并发锁,解析Synchronized锁升级

六月ゝ 毕业季﹏ 提交于 2020-02-09 17:06:40
这篇文章分为六个部分,不同特性的锁分类,并发锁的不同设计,Synchronized中的锁升级,ReentrantLock和ReadWriteLock的应用,帮助你梳理 Java 并发锁及相关的操作。 一、锁有哪些分类 一般我们提到的锁有以下这些: 乐观锁/悲观锁 公平锁/非公平锁 可重入锁 独享锁/共享锁 互斥锁/读写锁 分段锁 偏向锁/轻量级锁/重量级锁 自旋锁 上面是很多锁的名词,这些分类并不是全是指锁的状态,有的指锁的特性,有的指锁的设计,下面分别说明。 1、乐观锁 VS 悲观锁 乐观锁与悲观锁是一种广义上的概念,体现了看待线程同步的不同角度,在Java和数据库中都有此概念对应的实际应用。 (1)乐观锁 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。 乐观锁适用于多读的应用类型,乐观锁在Java中是通过使用无锁编程来实现,最常采用的是CAS算法,Java原子类中的递增操作就通过CAS自旋实现的。 CAS全称 Compare And Swap(比较与交换),是一种无锁算法。在不使用锁(没有线程被阻塞)的情况下实现多线程之间的变量同步。java.util.concurrent包中的原子类就是通过CAS来实现了乐观锁。 简单来说,CAS算法有3个三个操作数:

进程和线程

我怕爱的太早我们不能终老 提交于 2020-02-09 09:35:25
计算机是完成特定任务的工具,我们把特定的任务称为task。最早的计算机是单task系统,需要手动装载,启动task的程序,所有的资源由该task独占,一个task完成后才能启动下一个task。操作系统的一个重要功能是管理task,为task分配系统资源。进程是操作系统分配资源和调度task的基本单位。 进程是一个具有一定独特功能的程序在一个数据集合上的一次动态执行。进程由代码块(静态,二进制),数据集,进程控制块(动态)三部分组成。进程概念的引入是为了便于理解操作系统对task管理。进程是操作系统为task分配系统资源的基本单位,也是task调度的基本单位。 线程是CPU计算流的抽象,一般认为它由程序计数器(PC),栈和寄存器组构成。从操作系统的角度来看,线程使资源和计算流分离,多个线程可以共享系统资源,实现了系统资源(内存,文件,信号)的高效利用。同时,这种共享也实现了计算流之间更高效的交互,实现更高的并行和并发度。 POSIX的使用 demo 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 #include <sys

C语言 pthread_create

蹲街弑〆低调 提交于 2020-02-08 12:56:36
基础 注意编译多线程程序的时候要添加 -lpthread 参数 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); 参数1:初始化线程类型的变量 参数2:通常传NULL,表示使用线程默认属性。 参数3:函数指针,该函数运行结束,则线程结束。 参数4:函数的参数 返回值:成功:0; 失败:错误号 # include <stdio.h> # include <pthread.h> # include <unistd.h> void * tfn ( void * arg ) //线程函数 { printf ( "线程 Thread_ID = %lu\n" , pthread_self ( ) ) ; return NULL ; } int main ( void ) { pthread_t tid ; pthread_create ( & tid , NULL , tfn , NULL ) ; //创建线程 sleep ( 1 ) ; //等待线程结束 printf ( "进程,pid = %d\n" , getpid ( ) ) ; return 0 ; } 来源: CSDN 作者: Claroja 链接: https

【Android】OOM问题分析

自古美人都是妖i 提交于 2020-02-07 08:06:05
OOM问题分析 简介 OOM(OutOfMemoryError),最近线上版本出现了大量线程OOM的crash,尤其是华为Android 9.0系统的手机,占总OOM量的85%左右。 OOM分类 [XXXClassName] of length XXX would overflow“是系统限制String/Array的长度所致,这种情况比较少。 java.lang.OutOfMemoryError: “Failed to allocate a " << byte_count << " byte allocation with " << total_bytes_free << " free bytes and " << PrettySize(GetFreeMemoryUntilOOME()) << " until OOM”; 通常情况下是因为 java 堆内存不足导致的,即 Runtime.getRuntime().maxMemory() 获取到的最大内存无法满足要申请的内存大小时,这种情况比较好模拟,例如我们可以通过 new byte[] 的方式来申请超过 maxMemory() 的内存,但是也有一些情况是堆内存充裕,而且设备内存也充裕的情况下发生的。 java.lang.OutOfMemoryError: Could not allocate JNI Env(代号JNIEnv)