0

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

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->head' 标记为 volatile,但如果另一个中断恰好在 'head' 的增加和对 'dest' 的分配之间排除,事情可能会出错。

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

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

4

2 回答 2

0

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

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

不要那样做。

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

于 2013-01-21T10:20:15.510 回答
0

想想信号中断信号......如果你真的需要:

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

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

于 2013-01-21T11:07:46.710 回答