gpt4 book ai didi

c - 使用 pthread_sigmask() 保护 sem_wait() 不受信号影响

转载 作者:太空狗 更新时间:2023-10-29 11:13:37 27 4
gpt4 key购买 nike

我有一个通过第 3 方库访问硬件资源 (SPI) 的库。我的库以及 SPI 资源被多个进程访问,所以我需要用信号量锁定资源,锁定函数如下:

static int spi_lock(void)
{
struct timespec ts;

if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
{
syslog(LOG_ERR,"failed to read clock: %s\n", SPISEM, strerror(errno));
return 3;
}
ts.tv_sec += 5;
if (sem_timedwait(bcoms->spisem, &ts) == -1)
{
syslog(LOG_ERR,"timed out trying to acquire %s: %s\n", SPISEM, strerror(errno));
return 1;
}
return 0;
}

static int spi_unlock(void)
{
int ret = 1;

if (sem_post(bcoms->spisem))
{
syslog(LOG_ERR,"failed to release %s: %s\n", SPISEM, strerror(errno));
goto done;
}
ret = 0;
done:
return ret;
}

现在我的问题是该库在守护进程中使用,并且该守护进程通过终止信号停止。有时我在持有信号量锁时收到终止信号,因此服务器无法成功重启,因为锁被永久占用。为了解决这个问题,我试图阻止信号,如下所示(我正在等待硬件在 atm 上测试它):

static int spi_lock(void)
{
sigset_t nset;
struct timespec ts;

sigfillset(&nset);
sigprocmask(SIG_BLOCK, &nset, NULL);

if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
{
syslog(LOG_ERR,"failed to read clock: %s\n", SPISEM, strerror(errno));
return 3;
}
ts.tv_sec += 5; // 5 seconds to acquire the semaphore is HEAPS, so we better bloody get it !!!
if (sem_timedwait(bcoms->spisem, &ts) == -1)
{
syslog(LOG_ERR,"timed out trying to acquire %s: %s\n", SPISEM, strerror(errno));
return 1;
}
return 0;
}

static int spi_unlock(void)
{
sigset_t nset;
int ret = 1;

if (sem_post(bcoms->spisem))
{
syslog(LOG_ERR,"failed to release %s: %s\n", SPISEM, strerror(errno));
goto done;
}

sigfillset(&nset);
sigprocmask(SIG_UNBLOCK, &nset, NULL);
ret = 0;
done:
return ret;
}

但是在阅读 sigprocmask() 的手册页后,它说在多线程系统中使用 pthread_sigmask(),而我想要保护的服务器之一将是多线程的。我不明白的是,如果我在库中使用 pthread_sigmask(),并且主父线程生成一个 SPI 读取线程,该线程使用我库中的那些锁定函数,读取线程将受到保护,但主线程不能当我持有互斥锁并且在读取线程上禁用信号让我无处可去时,仍然收到终止信号并关闭守护进程?如果是这样,是否有更好的解决方案来解决这个锁定问题?

谢谢。

最佳答案

事实上,您已经正确地分析了问题 - 屏蔽信号并不能保护您。屏蔽信号不是防止进程因处于不一致状态的共享数据(如文件或共享信号量)而终止的正确工具。

如果您想在某些信号下正常退出,您可能应该做的是让程序安装信号处理程序来捕获终止请求并将其提供给您的正常程序逻辑。您可以使用多种方法:

  1. 通过管道将终止请求发送给您自己。如果您的程序是围绕一个可以等待管道输入的 poll 循环构建的,那么这会很有效。

  2. 使用 sem_post,一个异步信号安全的同步函数,将信号报告给程序的其余部分。

  3. 从主线程启动一个专用的信号处理线程,然后阻塞主线程中的所有信号(以及通过继承,阻塞所有其他新线程)。这个线程可以只执行 for(;;) pause(); 并且因为 pause 是异步信号安全的,你可以从信号处理程序调用你想要的任何函数 - - 包括与其他线程同步所需的 pthread 同步函数。

请注意,这种方法仍然不是“完美”的,因为您永远无法捕获或阻止 SIGKILL。如果用户决定使用 SIGKILL (kill -9) 终止您的进程,那么信号量可能会处于不良状态,您也无能为力。

关于c - 使用 pthread_sigmask() 保护 sem_wait() 不受信号影响,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29087614/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com