如何在C中编写“线程安全”功能?

时间:2010-04-03 08:03:55

标签: c thread-safety

您好我在C中编写了一些数据结构,并且我意识到它们的相关函数不是线程安全的。我正在编写的代码只使用标准C,我希望实现某种“同步”。

我在考虑做这样的事情:

enum sync_e { TRUE, FALSE };
typedef enum sync_e sync;


struct list_s {
//Other stuff
    struct list_node_s *head;
    struct list_node_s *tail;
    enum sync_e locked;
};
typedef struct list_s list;

,在列表结构中包含一个“boolean”字段,表示结构状态:locked,unlocked。

例如,插入函数将以这种方式重写:

int list_insert_next(list* l, list_node *e, int x){
    while(l->locked == TRUE){
        /* Wait */
    }
    l->locked = TRUE;
    /* Insert element */
    /* -------------- */
    l->locked = FALSE;
    return (0);
}

在列表上操作时,“锁定”字段将设置为TRUE,不允许任何其他更改。操作完成后,“锁定”字段将再次设置为“TRUE”。

这种做法好吗?您是否了解其他方法(仅使用标准 C)。

5 个答案:

答案 0 :(得分:5)

标准C不会“知道”有关线程的任何信息。任何与线程本身相关的线程,同步原语,原子操作都不是语言或标准库的一部分。它们始终是POSIX或Windows API等系统库的一部分。

因此,当多个线程仅使用标准C使用数据结构时,无法保护您的数据结构免受竞争条件的影响。

如果您的结构实例仅由单个线程使用,则可以在多线程场景中使用它,例如不要在函数中使用静态变量。

答案 1 :(得分:3)

您的代码可能会导致race condition.您应该使用互斥锁。

答案 2 :(得分:1)

不幸的是,我不认为Ansi C提供了互斥机制......它也没有提供多重机制。

如果您想获得可移植的多线程代码,您可以选择posix这样的原始集。当然这只能在Unix系统上移植。所以,如果你想要一个建议,你应该针对一些高级库进行编程,包含不同系统上的包装线程和互斥锁。我认为glib应该做你需要的。

答案 3 :(得分:1)

无法保证

l->locked = TRUE;

将在单个原子操作中立即发生。它可能被编译成几个CPU指令(取决于CPU架构,编译器,操作系统等)。

您应该使用环境提供的同步机制。这些超出了C标准的范围。

答案 4 :(得分:1)

原则是可以的,具体取决于您的平台。 如果你有一个非常简单的处理器并且资源在两个中断例程之间共享,那么这可能就足够了。

你应该警惕竞争条件和优先级倒置,查一查。