我尝试在D语言中实现类似无锁的fixedsize队列
import core.atomic;
struct Chunk(T, uint N)
{
T[N] data;
shared uint count_;
shared uint queueCounter;
@property bool full() { return count_ == N; }
void append(T value)
{
atomicOp!("+=")(queueCounter, 1);
while(1)
{
uint c = count_;
if(cas(&count_, c, c + 1))
{
data[c] = value;
atomicOp!("-=")(queueCounter, 1);
break;
}
}
}
bool wait()
{
if(!full())
{
return false;
}
while(0 != queueCounter) {}
return true;
}
}
称之为:
import std.parallelism;
struct S
{
bool dirty;
int time;
int[16] data;
}
int main(string[] argv)
{
const uint N = 14343;
Chunk!(S, N) ch;
foreach(i; taskPool.parallel(std.range.iota(N), 10))
{
S item;
item.time = i;
ch.append(item);
}
while(!ch.wait()) {}
// DONE
return 0;
}
它适用于N == 14343
,但在没有任何14344消息的情况下失败(值取决于S.sizeof
)。
为什么程序失败?
我正在做正确的CAS追加吗?
“DONE”字符串后是否可以完全访问chunk.data
?
答案 0 :(得分:2)
看起来你在Windows上运行它,默认堆栈大小为1 MB(至少根据this article at MSDN)。
你的S.sizeof
可能是72,它不会超过14563个S
个实例(堆栈上还有其他东西,因此你的最大N
略低一些)。< / p>
在堆栈上放置一个较大的变量会导致堆栈溢出,这应该在调用main时立即发生:ch
然后被分配Chunk!(S, N).init
的值,这会导致写入外部堆栈边界,命中一个保护页面,因此崩溃程序时出现分段错误(至少这是Linux N
大到足以溢出默认的8兆字节堆栈时的结果),或者,在Windows术语中,是访问冲突(我现在没有Windows框验证它。)
有一些解决方案:
N
。data
。