当多个线程共享相同的内存时,需要确保每个线程看到一致的数据视图,当多个线程同时去修改这片内存时,就可能出现偏差,得到与预期不符合的值。为啥需要同步,一件事情逻辑上一定是有序的,即使在并发环境下;而操作系统对于多线程不会自动帮我们串行化,所以需要我们通过操作系统提供的同步方式api,结合自己的业务逻辑,利用多线程提高性能的同时,保证业务逻辑的正确性。一般而言,linux下同步方式主要有4种,原子锁,互斥量,读写锁和条件变量。下面一一介绍几种同步方式。

1. spinlock

1)  概念

spinlock是一种互斥结构,通过CPU提供的特殊的原子指令集合实现互斥地访问一个资源,需要硬件支持。一个线程访问数据未结束的时候,其他线程不得对同一个数据进行访问。

2)  实现

spinlock一般基于原子的read-modify-write操作实现。read-modify-write操作允许一个CPU读取一个值,修改该值,并将修改完成的值回写内存的三个操作作为一个原子总线操作,因此需要CPU特殊支持。具体而言,通过test-and-set指令实现,从内存中读取一个值,然后和0比较,并且将内存中的值设置为1。

3) 相关函数

a) 原子操作

   test_and_set(volatile int* addr, value)
{
return os_atomic_test_and_set_int(addr,value);
}

这里volatile修饰词告诉编译器从内存中获取,保证正确性,避免从寄存器中读取到不准确的值。

b) 设置锁变量

 set_spinlock(lock_word)
{
int i = ;
int value;
while (true)
{
value = test_and_set(&lock_word, );
if (value == ) //尚未被占用,可以获取
break;
else //已经被其他线程占用,继续轮转
do nothing
}
}

c)       重置锁变量

 reset_spinlock(lock_word)
{
test_and_set (lock_word, );

2.  mutex

1) 概念

与 spinlock作用相同,保证互斥地访问一个资源。

2) 相关函数

int pthread_mutex_lock(pthread_mutex_t *mutex)

int pthread_mutex_trylock(pthread_mutex_t *mutex)

int pthread_mutex_unlock(pthread_mutex_t *mutex)

pthread_mutex_trylock()语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待。

3)  spinlock与mutex的区别

a) 作用范围,mutex是内核对象,可以在多线程,多进程同步中使用;spinlock作用范围仅限于本进程(锁变量是进程内的),仅适用于多线程同步。

b) spinlock依赖于硬件的原子操作指令

c) 线程获取spinlock失败时,会采取循环等待的方式,此时线程处于运行状态,CPU空转;而获取mutex失败时,线程会挂起,线程处于wait状态,不会被内核调度。

d) 由于3的特点,进入等待状态或从等待状态被唤醒,都涉及到CPU的上下文切换,而CPU切换是比较耗时的,一般需要25us。相对而言spinlock则没有这样的代价,效率更高。

e) 也由于3的特点,spinlock会空转,导致浪费大量的CPU时间片,若用户持有锁时间长,导致空转时间长,也得不偿失。因此spinlock比较适合于“快拿快放”的使用场景。

3.读写锁

1) 概念

spinlock和互斥量都是保证同一时刻只有一个线程操作共享内存。互斥锁要么是加锁状态,要么是不加锁状态,一次只有一个线程可以对其加锁。读写所可以有3种状态,读模式下加锁状态,写模式下加锁状态,不加锁状态。相对于前两者,读写锁有更高的并发度,允许多个线程同时读共享内存。

2) 相关函数

pthread_rwlock_rdlock(pthread_rwlock_t*);  读锁定

pthread_rwlock_tryrdlock(pthread_rwlock_t*); 非阻塞读锁定

pthread_rwlock_wrlock(pthread_rwlock_t*); 写锁定

pthread_rwlock_trywrlock(pthread_rwlock_t*); 非阻塞写锁定

pthread_rwlock_unlock(pthread_rwlock_t*);  释放锁

4. 条件变量

1) 概念

条件变量是另外一种同步机制,通过与互斥锁配合使用,利用锁保护条件变量,通过条件变量实现唤醒和等待的机制。通过这种方式,允许线程以无竞争的方式等待特定的条件发生

2) 相关函数

int pthread_cond_signal(pthread_cond_t *cond);  //唤醒等待条件某个线程

int pthread_cond_broadcast(pthread_cond_t *cond); //唤醒等待条件所有线程

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); //等待条件发生。

3) 说明

调用pthread_cond_wait之前,需要线程获取互斥量,调用者把互斥量传递给函数,函数把调用线程发到等待队列上,然后对互斥量解锁,这个操作是原子操作。当pthread_cond_wait返回时,互斥量会再次被锁住,这个实现都在pthread_cond_wait函数中实现,不需要用户逻辑介入。

Linux多线程同步方式的更多相关文章

  1. Linux多线程同步机制

    http://blog.163.com/he_junwei/blog/static/19793764620141711130253/ http://blog.csdn.net/h_armony/art ...

  2. linux多线程同步pthread_cond_XXX条件变量的理解

    在linux多线程编程中,线程的执行顺序是不可预知的,但是有时候由于某些需求,需要多个线程在启动时按照一定的顺序执行,虽然可以使用一些比较简陋的做法,例如:如果有3个线程 ABC,要求执行顺序是A-- ...

  3. linux多线程同步的四种方式

    1. 在并发情况下,指令执行的先后顺序由内核决定.同一个线程内部,指令按照先后顺序执行,但不同线程之间的指令很难说清楚是哪一个先执行.如果运行的结果依赖于多线程执行的顺序,那么就会形成竞争条件,每次运 ...

  4. C++实现一个多线程同步方式的协同工作程序示例

    多线程并发程序与协同程序其实是不同的概念.多线程并发是多个执行序同时运行,而协同程序是多个执行序列相互协作,同一时刻只有一个执行序列.今天想到的是将两者结合起来,拿现实生活中的例子来说,假设一个班级有 ...

  5. Linux多线程同步之相互排斥量和条件变量

    1. 什么是相互排斥量 相互排斥量从本质上说是一把锁,在訪问共享资源前对相互排斥量进行加锁,在訪问完毕后释放相互排斥量上的锁. 对相互排斥量进行加锁以后,不论什么其它试图再次对相互排斥量加锁的线程将会 ...

  6. linux多线程同步

    1. 互斥量是线程同步的一种机制,用来保护多线程的共享资源.同一时刻,只允许一个线程对临界区进行访问.互斥量的工作流程:创建一个互斥量,把这个互斥量的加锁调用放在临界区的开始位置,解锁调用放到临界区的 ...

  7. Linux多线程与同步

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 典型的UNIX系统都支持一个进程创建多个线程(thread).在Linux进程基础 ...

  8. Linux 多线程 - 线程异步与同步机制

    Linux 多线程 - 线程异步与同步机制 I. 同步机制 线程间的同步机制主要包括三个: 互斥锁:以排他的方式,防止共享资源被并发访问:互斥锁为二元变量, 状态为0-开锁.1-上锁;开锁必须由上锁的 ...

  9. Linux多线程--使用信号量同步线程【转】

    本文转载自:http://blog.csdn.net/ljianhui/article/details/10813469 信号量.同步这些名词在进程间通信时就已经说过,在这里它们的意思是相同的,只不过 ...

随机推荐

  1. Raising Error Conditions with MySQL SIGNAL / RESIGNAL Statements

    http://www.mysqltutorial.org/mysql-signal-resignal/ Summary: in this tutorial, you will learn how to ...

  2. 怎样给Eclipse添加一个Xml模板

    1.找到Window/Preferences/XML/XML Files/Editor/Templates 2.新建一个模板,设置一个名称并且在Pattern中设置自己的XML模板就可以了,同时支持导 ...

  3. No.014:Longest Common Prefix

    问题: Write a function to find the longest common prefix string amongst an array of strings. 官方难度: Eas ...

  4. Python WMI获取Windows系统信息 监控系统

    #!/usr/bin/env python # -*- coding: utf-8 -*- #http://www.cnblogs.com/liu-ke/ import wmi import os i ...

  5. 七个结构模式之装饰者模式(Decorator Pattern)

    定义: 使用组合的方法,动态给一个类增加一些额外的功能,避免因为使用子类继承而导致类继承结构复杂.并且可以保持和被装饰者同一个抽象接口,从而使客户端透明. 结构图: Component:抽象构件类,定 ...

  6. 双重OAuth 2.0架构

    OAuth 2.0支持几种grant type,由于安全性不同,所以适用范围也不同.背景知识:<理解OAuth 2.0> grant type 是否需要secret 是否出现授权界面 授权 ...

  7. webkit中获取用户选择文本和编程设定选择文本

    一.需求背景 在 Android 应用中,内嵌一个 WebView,希望捕获用户点击事件,通过 javascript 判断用户点击的是否英文单词,如果是则将被点击单词发给应用做进一步处理,并实用 ja ...

  8. [转]DevExpress v13.2 Beta版重要更新

    昨日,DevExpress隆重宣布发布v13.2.3测试版,想抢先尝鲜的朋友可以在这里下载哦.希望使用DevExpress旧版本的朋友,看到这些更新后能尽快更新你的代码,以免造成不必要的麻烦. Das ...

  9. 如何在Infraworks中创建多树种组成的森林

    在Infraworks 2014中,你可以有shp文件导入生成树木和森林,也可以直接在模型中规划一片区域作为森林.美中不足的就是,这些充其量叫树林不能叫森林,因为他们的样式都是一个树种,而真正的森林肯 ...

  10. JavaScript MVC框架和语言总结[infoq]

    infoq关于javascript的语言和框架的总结,非常全面,值得一读. http://www.infoq.com/minibooks/emag-javascript Contents of the ...