使用无锁的fixedsize队列失败

时间:2016-03-31 11:37:10

标签: d cas lock-free

我尝试在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

1 个答案:

答案 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框验证它。)

有一些解决方案:

  1. 使用较小的N
  2. 增加堆栈大小(请参阅上面链接的文章)。
  3. 在堆上分配data