2 u010484936 u010484936 于 2016.01.27 04:41 提问

一个完全无锁无原子的疑问,以及猜想?

先基于一个单生产单消费的情况,我写了如下一个class:
template
class SingleLockFree
{
public:
SingleLockFree()
{
m_tail = new Node();
m_Head = m_tail;
}
~SingleLockFree()
{
//做最后未处理的内存的释放
}
void Push(T t)//生产线程
{
Node* p = new Node();//内存分配待优化
m_tail->_data = t;
m_tail->_next = p;
m_tail = p;
}

bool Pop(T& t)//消费线程
{
if (m_Head == m_tail)
return false;
Node* p = m_Head;
m_Head = p->_next;
t = p->_data;
delete p;
return true;
}
private:
struct Node
{
T _data;
Node* _next = nullptr;
};
Node* m_Head;//头
Node* m_tail;//当前
};
这样只在一个生产线程和一个消费消费线程使用是不会出问题的吧?
既然有这种模式,那我们为什么不可以把多生产多消费把他单一化,比如说:1个生产者对应多个消费者,我们可以把一个生产者生产出来的产品对应成分成与多个消费者所对应。那么就不存在什么锁和原子了吧?同样的,对于多生产多消费的,我们可以以多的那一方(生产者或消费者)来划分。把少的以某种方法划分成多的那一方所对应的个数,这种模式只是在开启线程的时候耗一点(也许可能会加锁,但是只是在开线程的时候,这个时候来分配谁怎么生产,谁怎么消费),这样不就可以解决无锁无原子?当然这个想法只是在某些领域好用,我是一个写游戏后台的,所以考虑得比较局限,还请多多指教

2个回答

caozhy
caozhy   Ds   Rxr 2016.01.27 07:34

你的代码不同步肯定不行,因为线程可以在函数执行到任何地方,甚至一条语句执行了一半被切换到另一个线程,它们不是原子化的。

u010484936
u010484936 回复caozhy: 这个代码的核心思想就是在m_tail=p这一行,这行代码会被翻译成多行汇编?或者说这行代码执行到一半就已经算他被赋值了?我所知道的是cpu都是以汇编指令为单位来计算吧?如果这行代码不会被解释成多行汇编指令,那么这个猜想我觉得还是成立的
2 年多之前 回复
xyz347
xyz347   2016.01.27 08:19

你这段代码本身就不是lock free的

xyz347
xyz347 仔细分析了一下,你说的是对的,单生产单消费场景是lock free的,很棒的思路。
2 年多之前 回复
u010484936
u010484936 回复xyz347: 我知道你说的,i++和++i翻译成汇编都是三条指令,但是我这里就只需要保证m_tail=p是一条汇编指令就ok了,其他的我完全不关系然而我看了这个赋值的汇编,
2 年多之前 回复
xyz347
xyz347 连++i之类的操作都不是原子的,更别说链表操作了。我实实在在的遇到过一个bug,简化了说就是一个全局变量int i=0,一个线程负责++i,一个负责--i,两个线程各跑一万次,结果i不是0。 原因是++i有三步: 从内存加载到寄存器 寄存器加1 保存到内存中 如果第一步之后,线程被打断了,那么结果就是错的。比如初始值是0,那么加载到寄存器的值是0,被--i的线程打断,--i之后i是-1,然后++i继续执行,而寄存器的值是0,+1之后是1
2 年多之前 回复
u010484936
u010484936 回复xyz347: 为何这么说?只是两根线程跑,一个生产者线程,一个消费者线程
2 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!
其他相关推荐
双向无锁链表(未完成)
看到一些大牛关于无锁双向
Java无锁队列与栈的实现
参考:《Implementing Lock-Free Queues》。       尽管这篇文章讲的是无锁队列,但是引用《Java并发实践》中的一句话,并发环境下,首先应该保证正确性,其次才是性能。在没有证明现情况下性能确实需要提高,且锁机制无法满足的时候,才应该考虑无锁。确实,无锁实现的难度随着需求要求会迅速提高,相对于锁机制,难把控的多。      无锁的基础是CAP(Compare An
用原子操作实现无锁编程
假设我们要维护一个全局的线程安全的 int 类型变量 count, 下面这两行代码都是很危险的: count ++; count += n; 我们知道, 高级语言中的一条语句, 并不是一个原子操作. 比如一个最简单的自增操作就分为三步:  1. 从缓存取到寄存器 2. 在寄存器加1 3. 存入缓存。 多个线程访问同一块内存时, 需要加锁来保证访问操作是互斥的.  所以, 我
无锁编程(二) - 原子操作
介绍了无锁编程之原子操作的概念,原理和原子操作的几种类型及使用方法,对原子操作和互斥锁的性能也进行一些对比
linux无锁编程
简单的笔记,未完待续 一道题: 无锁化编程有哪些常见方法? 针对计数器,可以使用原子加只有一个生产者和一个消费者,那么就可以做到免锁访问环形缓冲区(Ring Buffer)RCU(Read-Copy-Update),新旧副本切换机制,对于旧副本可以采用延迟释放的做法  CAS(Compare-and-Swap),如无锁栈,无锁队列等待 解析: 一、RCU    
无锁数据结构(基础篇):原子核、原子性、基本类型
无锁数据结构基于两方面——原子性操作以及内存访问控制方法。本文中我话题主要涉及原子性和原子性基本类型。 在开始之前,我对大家表示感谢,谢谢你们对初识无锁数据结构的热爱。看到大家对无锁话题很感兴趣,我感到很开心。我计划依据学术概念将此做成一个系列,从基础到算法,同时以 text 的形式展示 libcds 中的代码实现。但有些读者希望避开漫谈,尽快展示这些代码,以及如何利用这些库。我同意其中的一些观
C++原子性实现无锁队列
转载于http://coolshell.cn/articles/8239.html 关于无锁队列的实现,网上有很多文章,虽然本文可能和那些文章有所重复,但是我还是想以我自己的方式把这些文章中的重要的知识点串起来和大家讲一讲这个技术。下面开始正文。 关于CAS等原子操作 在开始说无锁队列之前,我们需要知道一个很重要的技术就是CAS操作——Compare & Set,或是 Com
基于C++ STL利用CAS原子操作封装的无锁list
在做高吞吐量的项目中,性能是必须考虑的一个重要因素。而数据同步则又是重中之重,常常需要使用到锁,但是锁的使用会造成性能下降。这个时候,CAS就大显身手了,关于CAS,这里就不再多说。直接贴我基于STL list的封装的无锁list,其他容器则类似。 文件1:lockfree_list.hpp #ifndef LOCK_FREE_LIST_HPP #define LOCK_FREE_LIST
Linux用户层多线程无锁化原子操作
Linux用户层多线程无锁化原子操作
实现一个无锁的Stack,并写一段测试代码(多线程访问),证明这个Stack是线程安全的。给出程序以及运行的截图。
实现一个无锁的Stack,并写一段测试代码(多线程访问),证明这个Stack是线程安全的。给出程序以及运行的截图。 //关键点:无锁须利用CAS类 //data static private AtomicInteger j = new AtomicInteger(0); //控制插入的指针 static private AtomicInteger