我必须编写一个线程安全库,它使用 POSIX 信号量(用作初始值 = 1 的互斥体)进行同步。我发现正确管理异步信号存在一些问题。我有一个链接到这个静态库的应用程序,并且该应用程序(多线程)调用库的函数。对某些内部结构的访问由 posix 信号量控制(它在库内部):
void library_func1(lib_handler *h)
{
sem_wait(sem);
/* do some stuff with global data */
sem_post(sem);
}
void library_func2(lib_handler *h)
{
sem_wait(sem);
/* do some stuff with global data */
sem_post(sem);
}
void library_close(lib_handler *h)
{
...
}
如果一个线程锁定信号量时引发异步信号(比方说 SIGINT
),会附加什么内容?如果我重新启动应用程序,我将陷入死锁,因为信号量存在并且其值为 0
。有一个函数library_close
可以在引发异步信号时释放信号量,但这是执行和检查此操作的最佳方法(我认为只有在exit
之后该函数才是信号安全的)?在多线程应用程序中,通常最好的做法是为所有信号使用单个线程管理器:该线程应该位于库中还是可以在应用程序中启动它?
谢谢大家。
请您参考如下方法:
Linux futexes 也有同样的问题。它不能完全解决,但您可以做的是将锁定信号量的进程的 pid 写入同一共享内存区域中的某处。如果另一个进程尝试锁定信号量并且花费了太长时间(对于某些“太长”值),它会通过从共享内存中读取 pid 来找出哪个进程锁定了信号量。如果该进程不再存在,您就知道自己陷入了死锁(并且您可能应该死掉,因为库的内部数据可能处于不一致的状态)。
这仍然存在一个小竞争,因为获取锁定的进程可能会在锁定之后但在写入其 pid 之前死亡。 AFAIK 使用信号量无法避免这种情况。 (如果您有一个锁实现,其中 pid 在获取时自动写入锁变量,那么它可能会起作用,但您可能需要自己编写它。)