无锁缓冲区

时间:2013-01-21 10:09:24

标签: c thread-safety locking buffer c99

在我的代码中,我有一个缓冲区,我向其添加数据的代码是:

bool push_string(file_buffer *cb, const char* message, const unsigned short msglen)
{
    unsigned int size = msglen;

    if(cb->head >= (cb->size - size))
    {
        size = cb->size - cb->head - 1;
    }

    if(size < 1) return false;

    char* dest = cb->head += size;

    memcpy(dest, message, size);

    return (size == msglen);
}

由于我从多个中断添加数据(可以互相豁免),我想知道这段代码是否是线程安全的?我将'cb-&gt; head'标记为易失性,但如果另一个中断在“head”的增加与'dest'的对齐之间完全豁免,则可能出现问题。

如何改进此代码以使其更安全?

编辑:也许我不应该使用'线程安全'一词,因为没有并行运行的线程,只有中断的可能性。

2 个答案:

答案 0 :(得分:0)

C99没有线程的概念,因此也没有线程保存。只有C11有。 在C99中,唯一的中断安全数据类型是sig_atomic_t,但显然这也没有说明线程。

通常,您在尝试同时访问数据结构时完全错误,volatile并不能保证您收到合理的数据。即使在C11中也不能保证任何操作的原子性,因此你可能会出现指针值的下半部分已被写入但不是上半部分的情况。这可能会给你一个完全虚假的结果。由于这样的事情可能只发生在一百万次或特殊情况下(例如重负荷),这可能导致很难追查的错误。

不要那样做。

C11为您提供了处理此类事物的新工具,特别是原子操作。它没有完全实现,但许多编译器已经有可以帮助你的扩展。我在P99宏包中包含了其中的一些内容,因此对于某些编译器,您可以从今天开始使用这些功能。

答案 1 :(得分:0)

考虑信号中断信号......如果你真的需要它:

您可以在push_string()中阻止所有相关信号。

另一个依赖于应用程序的可能性可能是将信号处理程序代码移动到主“线程”中(信号处理程序代码只生成唤醒主要执行线程的“事件”)。我没有足够的关于你的应用的信息,说它是不是一个好的选择。