【发布时间】:2015-03-16 21:51:51
【问题描述】:
我有一个通过第三方库访问硬件资源 (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) 删除信号量,然后创建一个新信号量 2) 在服务器打开信号量时使用“create”标志,或 3) 仅使用控制函数将信号量重置为其初始状态。
-
您可能希望在“拥有”设备时锁定文件,而不是使用信号量。当拥有它的进程终止时,文件锁将自动解除。
标签: c linux multithreading