您好我在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)。
答案 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)
原则是可以的,具体取决于您的平台。 如果你有一个非常简单的处理器并且资源在两个中断例程之间共享,那么这可能就足够了。
你应该警惕竞争条件和优先级倒置,查一查。