两线程间无锁进行数据同步
2013-07-25 17:41
253 查看
转载自:http://blog.csdn.net/viewcode/article/details/7937665
线程间数据同步常用的方法就是加锁,但会引发程序挂起延迟的现象,在实时性较高的程序中不可取。
而无锁编程也有很多方法,如
http://www.ibm.com/developerworks/cn/linux/l-cn-lockfree/index.html
文章中,对多不同层级的数据同步方法有着详细的介绍。
据其介绍,两线程间环形缓存区无锁的方法能够比较好的解决读写问题。
我采用环形队列作为环形缓冲区的数据结构。
环形队列的实现方式也可分为线性和链式。对数据个数大小已知或在某个范围内控的情况,采用线性结构的队列,效率比较高;而对数据数量未知的情况,可采用链式结构。
在组织数据结构时,应小心以下几点:
1. 此解决方法适用于两线程间的读写问题;
2. 读者与写者必须先读写数据,后更新索引;
3. 读者线程只操作(更改)头索引,写者线程只操作(更改)尾索引,不能某线程同时操作两个索引。
4. 注意读写可能会发生溢出overflow的状况。读写前,进行判空与满的操作,若满,则需要丢数据。
5. 对线性环形队列的容量,可以设置为2^n,目的是提高循环操作取模%的效率(索引是单向递增的情况)。
对于溢出丢数据的情况,改进方法:
1. 对溢出的数据另外保存,然后加锁同步。这是个解决方法,但本身违背了原来无锁的初衷。
2. 采用链式结构作为缓冲区,数据操作频繁情况下,空间与时间的效率可能较低。嵌入式下,数据结构尽量有一个大小的限制,毕竟资源是有一定限制的,特别是在多个大的应用程序同时运行的状况下。
3. 两个队列,一个线性,一个链式,非溢出时使用线性队列处理数据;在溢出时,采用链式保存溢出的数据。够麻烦吧,效率与复杂度有时就是矛盾。
4. 丢就丢了吧,多测试丢包的情形,设置一个合理的大小,尽量减少丢数据的情况,不过,偶尔发生时,丢就丢了吧。
以上,仅仅是对两线程间数据传递的场景,无需加锁。若是多个线程同时读数据,就需要对读数据时,更改队列的代码加保护,加互斥器;同理,若是多个线程写数据,也需要对写队列的代码加互斥量。否则,仍会可能由于线程竞争造成数据被破坏的情况。 当然,写数据,和读数据 采用不同的互斥器。
----------------
今天跟几个做嵌入式的同事讨论,嵌入式下能否使用c++ STL,他们都不怎么应用STL的,原因是资源毕竟有限。
不过看网上的讨论,很多人还是支持使用STL,在编译器支持的情况下,提高开发效率。
在使用时,尽量注意下资源的使用情况,比如数据结构的大小有个限制,不要无限增大。(可能,随着软硬件资源的扩展,这种情况根本不用考虑了)
线程间数据同步常用的方法就是加锁,但会引发程序挂起延迟的现象,在实时性较高的程序中不可取。
而无锁编程也有很多方法,如
http://www.ibm.com/developerworks/cn/linux/l-cn-lockfree/index.html
文章中,对多不同层级的数据同步方法有着详细的介绍。
据其介绍,两线程间环形缓存区无锁的方法能够比较好的解决读写问题。
我采用环形队列作为环形缓冲区的数据结构。
环形队列的实现方式也可分为线性和链式。对数据个数大小已知或在某个范围内控的情况,采用线性结构的队列,效率比较高;而对数据数量未知的情况,可采用链式结构。
在组织数据结构时,应小心以下几点:
1. 此解决方法适用于两线程间的读写问题;
2. 读者与写者必须先读写数据,后更新索引;
3. 读者线程只操作(更改)头索引,写者线程只操作(更改)尾索引,不能某线程同时操作两个索引。
4. 注意读写可能会发生溢出overflow的状况。读写前,进行判空与满的操作,若满,则需要丢数据。
5. 对线性环形队列的容量,可以设置为2^n,目的是提高循环操作取模%的效率(索引是单向递增的情况)。
对于溢出丢数据的情况,改进方法:
1. 对溢出的数据另外保存,然后加锁同步。这是个解决方法,但本身违背了原来无锁的初衷。
2. 采用链式结构作为缓冲区,数据操作频繁情况下,空间与时间的效率可能较低。嵌入式下,数据结构尽量有一个大小的限制,毕竟资源是有一定限制的,特别是在多个大的应用程序同时运行的状况下。
3. 两个队列,一个线性,一个链式,非溢出时使用线性队列处理数据;在溢出时,采用链式保存溢出的数据。够麻烦吧,效率与复杂度有时就是矛盾。
4. 丢就丢了吧,多测试丢包的情形,设置一个合理的大小,尽量减少丢数据的情况,不过,偶尔发生时,丢就丢了吧。
以上,仅仅是对两线程间数据传递的场景,无需加锁。若是多个线程同时读数据,就需要对读数据时,更改队列的代码加保护,加互斥器;同理,若是多个线程写数据,也需要对写队列的代码加互斥量。否则,仍会可能由于线程竞争造成数据被破坏的情况。 当然,写数据,和读数据 采用不同的互斥器。
----------------
今天跟几个做嵌入式的同事讨论,嵌入式下能否使用c++ STL,他们都不怎么应用STL的,原因是资源毕竟有限。
不过看网上的讨论,很多人还是支持使用STL,在编译器支持的情况下,提高开发效率。
在使用时,尽量注意下资源的使用情况,比如数据结构的大小有个限制,不要无限增大。(可能,随着软硬件资源的扩展,这种情况根本不用考虑了)
相关文章推荐
- 线程间无需特别的手段进行通信,因为线程间可以共享数据结构,也就是一个全局变量可以被两个线程同时使用,不过要注意的是线程间需要做好同步。
- Java线程8:为什么进行数据同步
- sqlserver数据库进行数据和结构比较和同步 Visual Studio2017 数据库架构比较
- RedHat Linux下利用sersync进行实时同步数据
- Solr(搜索引擎服务)和MongoDB通过mongodb-connector进行数据同步的解决方案,以及遇到的各种坑的总结(针对solr-5.3.x版本),mongodb和solr实现实时增量索引
- Java多线程初学者指南(2):为什么要进行数据同步
- 用c#进行移动设备开发时rda同步数据时的设置详细过程
- 使用postgreSQL DataSync 进行pg数据库升级 数据同步 升级脚本生成, postgreSQL DataSync简单教程
- 使用postgreSQL DataSync 进行pg数据库升级 数据同步 升级脚本生成, postgreSQL DataSync简单教程
- windows下多个线程公用一个线程函数时候对某些变量需不需要进行同步的问题
- 对制造者线程和使用者线程进行同步(C# 编程指南)
- Java多线程初学者指南(9):为什么要进行数据同步
- 1.8.3挂起线程(数据不同步)
- 线程间数据同步-学习记录
- 使用rsync进行主机间数据同步及其他工具
- [数据同步] Linux与Windows进行数据同步
- 用互斥线程进行同步
- JAVA笔记14__多线程共享数据(同步)/ 线程死锁 / 生产者与消费者应用案例 / 线程池
- 使用postgreSQL DataSync 进行pg数据库升级 数据同步 升级脚本生成, postgreSQL DataSync简单教程
- 使用postgreSQL DataSync 进行pg数据库升级 数据同步 升级脚本生成, postgreSQL DataSync简单教程