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币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!