【问题标题】:fail with lock-free fixedsize queue无锁固定大小队列失败
【发布时间】:2016-07-19 20:13:09
【问题描述】:

我尝试用 D 语言实现无锁固定大小队列之类的东西

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 附加吗?

chunk.data 在“DONE”字符串之后是否可以完全访问?

【问题讨论】:

  • chunk.data 在 DONE 之后应该可以访问,只要函数还没有返回。但是,一旦函数返回,堆栈上的静态数组将无效,并且其中的任何切片也都指向垃圾。

标签: d cas lock-free


【解决方案1】:

您似乎在 Windows 上运行它,默认堆栈大小为 1 MB(至少根据 this article at MSDN)。

您的 S.sizeof 可能是 72,这给出了不超过 14563 个 S 实例(堆栈上还有其他东西,因此您的最大 N 略低)。

将较大的变量放在堆栈上会导致堆栈溢出,这应该在调用 main 时立即发生:然后将 ch 分配给 Chunk!(S, N).init 的值,这会导致写入堆栈边界外,触及保护页和因此导致程序因分段错误而崩溃(至少这是在 Linux 上N 大到足以溢出默认的 8 兆字节堆栈时的结果),或者,在 Windows 术语中,访问冲突(我没有Windows 框现在来验证它)。

有几个解决方案:

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

【讨论】:

    猜你喜欢
    • 2015-02-18
    • 1970-01-01
    • 2019-10-13
    • 1970-01-01
    • 2022-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多