多个线程同时写入单个缓冲区

时间:2016-06-20 03:57:25

标签: c++ multithreading

我有一个类似于此的输出标记:

struct cont {
    std::mutex m;
    size_t offset;
    char* data;

    cont(size_t sizeB) {
        data = new char[sizeB];
    }

    void write(char* data, size_t sizeB) {
        m.lock();
        size_t off = offset;
        offset += sizeB;
        m.unlock();
        std::memcpy(this->data + off, data, sizeB);
    }
};

我的想法是,我有许多线程,每个线程都在一个动态大小的工作负载上运行,并且没有特定的顺序将数据输出到该容器中。线程由服务器访问触发,并且不知道有多少并发或者它们将贡献多少。

我质疑这个的原因是因为你可以看到,主要工作负载在互斥锁之外,因为理论上只需要同步可用缓冲区的分配,并且线程不应该在该位之后发生冲突

到目前为止,它的工作正常,但从之前的经验来看,线程问题可以在未来发展,所以这被认为是线程安全的做法吗?

3 个答案:

答案 0 :(得分:2)

似乎没问题。如果要进行优化,可以使偏移成为原子,以完全避免互斥。所以,只需声明

std::atomic<size_t> offset;

并且可以删除互斥锁。

答案 1 :(得分:1)

就目前而言,我担心这是不完整的:您的解决方案在多个线程之间正确分配空间,但您还需要一个解决方案让线程“提交”其写入。想象一下,在memcpy中(甚至在开始记忆之前),一个作者线程被无限期地延迟。其他任何一个线程如何找到这个,以便最终可以使用这个缓冲区?

答案 2 :(得分:0)

这似乎非常安全。当偏移量变化不是4或8字节的倍数时,您可能会担心同时践踏“剩余”字节。我想通过引用标准来减轻您的顾虑,但memcpy的条目指向C库参考,这在细节上很少。尽管如此,该函数将缓冲区视为无符号字符的数组,因此它无法可靠地假设它还可以优化复制尾部的未对齐或不完整的单词,因为它可能构成一个越界访问。