- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有 3 个进程需要同步。进程一做某事然后唤醒进程二并休眠,进程二做某事然后唤醒进程三并休眠,进程三做某事并唤醒进程一并休眠。整个循环定时运行大约 25hz(由外部同步到进程一之前触发我的“真实”应用程序中的进程二引起)。我使用 sem_post 来触发(唤醒)每个进程,并使用 sem_timedwait() 来等待触发。
这一切都成功地运行了几个小时。然而,在某个随机时间(通常在两到四个小时之间的某处之后),其中一个进程在 sem_timedwait() 中开始超时,即使我确信信号量是通过 sem_post() 触发的。为了证明这一点,我什至在超时后立即使用了 sem_getvalue(),并且值为 1,因此应该触发了 timedwait。
请看下面的代码:
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <semaphore.h>
sem_t trigger_sem1, trigger_sem2, trigger_sem3;
// The main thread process. Called three times with a different num arg - 1, 2 or 3.
void *thread(void *arg)
{
int num = (int) arg;
sem_t *wait, *trigger;
int val, retval;
struct timespec ts;
struct timeval tv;
switch (num)
{
case 1:
wait = &trigger_sem1;
trigger = &trigger_sem2;
break;
case 2:
wait = &trigger_sem2;
trigger = &trigger_sem3;
break;
case 3:
wait = &trigger_sem3;
trigger = &trigger_sem1;
break;
}
while (1)
{
// The first thread delays by 40ms to time the whole loop.
// This is an external sync in the real app.
if (num == 1)
usleep(40000);
// print sem value before we wait. If this is 1, sem_timedwait() will
// return immediately, otherwise it will block until sem_post() is called on this sem.
sem_getvalue(wait, &val);
printf("sem%d wait sync sem%d. val before %d\n", num, num, val);
// get current time and add half a second for timeout.
gettimeofday(&tv, NULL);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = (tv.tv_usec + 500000); // add half a second
if (ts.tv_nsec > 1000000)
{
ts.tv_sec++;
ts.tv_nsec -= 1000000;
}
ts.tv_nsec *= 1000; /* convert to nanosecs */
retval = sem_timedwait(wait, &ts);
if (retval == -1)
{
// timed out. Print value of sem now. This should be 0, otherwise sem_timedwait
// would have woken before timeout (unless the sem_post happened between the
// timeout and this call to sem_getvalue).
sem_getvalue(wait, &val);
printf("!!!!!! sem%d sem_timedwait failed: %s, val now %d\n",
num, strerror(errno), val);
}
else
printf("sem%d wakeup.\n", num);
// get value of semaphore to trigger. If it's 1, don't post as it has already been
// triggered and sem_timedwait on this sem *should* not block.
sem_getvalue(trigger, &val);
if (val <= 0)
{
printf("sem%d send sync sem%d. val before %d\n", num, (num == 3 ? 1 : num+1), val);
sem_post(trigger);
}
else
printf("!! sem%d not sending sync, val %d\n", num, val);
}
}
int main(int argc, char *argv[])
{
pthread_t t1, t2, t3;
// create semaphores. val of sem1 is 1 to trigger straight away and start the whole ball rolling.
if (sem_init(&trigger_sem1, 0, 1) == -1)
perror("Error creating trigger_listman semaphore");
if (sem_init(&trigger_sem2, 0, 0) == -1)
perror("Error creating trigger_comms semaphore");
if (sem_init(&trigger_sem3, 0, 0) == -1)
perror("Error creating trigger_vws semaphore");
pthread_create(&t1, NULL, thread, (void *) 1);
pthread_create(&t2, NULL, thread, (void *) 2);
pthread_create(&t3, NULL, thread, (void *) 3);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
}
当程序正确运行时(在开始时以及随机但很长一段时间后),将打印以下输出。 sem1 的值在 thread1 等待之前始终为 1,因为它休眠了 40ms,此时 sem3 已触发它,因此它会立即唤醒。其他两个线程等待,直到从前一个线程接收到信号量。
[...]
sem1 wait sync sem1. val before 1
sem1 wakeup.
sem1 send sync sem2. val before 0
sem2 wakeup.
sem2 send sync sem3. val before 0
sem2 wait sync sem2. val before 0
sem3 wakeup.
sem3 send sync sem1. val before 0
sem3 wait sync sem3. val before 0
sem1 wait sync sem1. val before 1
sem1 wakeup.
sem1 send sync sem2. val before 0
[...]
但是,几个小时后,其中一个线程开始超时。从输出中可以看出信号量正在被触发,当我打印超时后的值时,它是1。所以sem_timedwait应该在超时之前就已经醒来了。我绝不会期望信号量的值在超时后为 1,除非触发发生在超时后但在我调用 sem_getvalue 之前,这种情况非常罕见(几乎肯定不会,但有可能发生)。
此外,一旦它开始失败,该信号量上的每个 sem_timedwait() 也会以同样的方式失败。请参阅以下输出,我对其进行了行编号:
01 sem3 wait sync sem3. val before 0
02 sem1 wakeup.
03 sem1 send sync sem2. val before 0
04 sem2 wakeup.
05 sem2 send sync sem3. val before 0
06 sem2 wait sync sem2. val before 0
07 sem1 wait sync sem1. val before 0
08 !!!!!! sem3 sem_timedwait failed: Connection timed out, val now 1
09 sem3 send sync sem1. val before 0
10 sem3 wait sync sem3. val before 1
11 sem3 wakeup.
12 !! sem3 not sending sync, val 1
13 sem3 wait sync sem3. val before 0
14 sem1 wakeup.
[...]
在第 1 行,线程 3(我在 printf 中混淆地称为 sem3)等待 sem3 被触发。在第 5 行,thread2 为 sem3 调用 sem_post。然而,第8行显示sem3超时,但是信号量的值为1。thread3随后触发sem1并再次等待(10)。但是,因为该值已经是 1,所以它会立即唤醒。它不会再次发送 sem1,因为这一切都发生在将控制权交给 thread1 之前,但是它随后再次等待(val 现在为 0)并且 sem1 被唤醒。这现在一直重复,sem3 总是超时并显示值为 1。
所以,我的问题是为什么sem3超时了,即使信号量已经被触发并且值明明是1?我绝不会期望在输出中看到第 08 行。如果它超时(因为,比如线程 2 已崩溃或花费的时间太长),该值应为 0。为什么它在进入此状态之前先正常工作 3 或 4 小时?
我尝试过使用三个独立的程序进行类似的测试,通过共享内存进行通信,而不是在同一程序中使用三个线程。这更接近于我的真实世界应用程序。结果和输出是一样的。问题确实出现在信号量(特别是 sem_timedwait 调用)中,而不是与 pthreads 有任何关系。
我还尝试了更短和更长的延迟,以及完全消除延迟,结果与上述类似。完全没有延迟,它有时会在几分钟而不是几小时后开始产生错误。这当然意味着可以更快地重现问题。
这是使用内核为 2.6.28 的 Ubuntu 9.4。同样的程序在 Redhat 和 Fedora 上运行正常,但我现在正在尝试移植到 Ubuntu。我也尝试过使用 Ubuntu 9.10,但没有任何区别。
感谢您的任何建议,吉尔斯
最佳答案
(很抱歉给出第二个答案,但是这个太乱了,无法通过编辑清理)
我认为答案已经在问题的原始帖子中。
So, my question is why does sem3 timeout, even though the semaphore has been triggered and the value is clearly 1? I would never expect to see line 08 in the output. If it times out (because, say thread 2 has crashed or is taking too long), the value should be 0. And why does it work fine for 3 or 4 hours first before getting into this state?
所以场景是:
sem_timedwait
中超时sem_getvalue
sem_post
在 sem3
sem_getvalue
并看到一个 1sem_post
在 sem1
这种竞争条件很难触发,基本上,您必须捕获一个线程在等待信号量时遇到问题的微小时间窗口,然后使用 sem_getvalue 读取信号量
。这种情况的发生在很大程度上取决于环境(系统类型、内核数量、负载、IO 中断),因此这解释了为什么它只在下类后发生,如果根本不发生的话。
让控制流依赖于 sem_getvalue
通常不是一个好主意。对sem_t
的唯一原子 非阻塞访问是通过sem_post
和sem_trywait
。
所以这个问题中的示例代码具有竞争条件。这并不意味着 gillez 的原始问题代码确实具有相同的竞争条件。也许这个例子太简单了,对他来说仍然是同样的现象。
我的猜测是,在他最初的问题中有一个未保护 sem_wait
。这是一个 sem_wait
,它只检查其返回值,而不检查 errno
,以防失败。如果进程有一些 IO,EINTR
确实会很自然地发生在 sem_wait
上。如果遇到 EINTR
,您只需执行 do - while
检查并重置 errno
。
关于c - Ubuntu : sem_timedwait not waking (C),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2928571/
我正在阅读有关sem_timedwait()的手册,但无法弄清楚该示例。我目前的理解是: 如果 sem_timedwait() 超时,则返回 -1 并将 errno 设置为 ETIMEDOUT。因此我
我写了一个小类,封装了共享锁和共享信号量。这些类通过了我所有的单元测试,除了一个:大约 60% 的时间使用 sem_timedwait 锁定共享内存信号量失败。这是我的代码: SharedLock::
我想在信号量上等待 20 英里秒,如下所示,但是当我打印 tv_sec 和 tv_nsec 的值时,它们的值变得非常大。 任何人都可以帮助理解下面的代码。 if (clock_gettime(CLOC
如果 10 秒后它不能减少信号量(另一个线程可以或不能增加它),我试图让我的程序中的线程停止我看到我可以为此使用 sem_timedwait() 但我无法在网上找到一个好的例子。所以我只想替换这个:
我使用 eCos 开发嵌入式系统:我在同一进程中有 2 个线程和 1 个信号量。 线程 A 将信号量初始化为 0,以便第一次尝试获取信号量时将被阻止。 线程 A 向线程 B 发送命令,并提供回调。 线
我尝试在 AIX 中使用 sem_timedwait。 我收到此错误: *“ld:0711-317 错误: undefined symbol :.sem_timedwait”* 我可以猜到,我缺少一些
我有 3 个进程需要同步。进程一做某事然后唤醒进程二并休眠,进程二做某事然后唤醒进程三并休眠,进程三做某事并唤醒进程一并休眠。整个循环定时运行大约 25hz(由外部同步到进程一之前触发我的“真实”应用
假设我有一个程序使用 sem_timedwait 等待 100 毫秒(获取当前时间,加上 100 毫秒,将结果用作 abs_timeout,cf. man page ).现在碰巧系统时间在等待信号量时
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); 的示例代码使用 CLOCK_REALTIME 作为 clock_g
我正在尝试使用 sem_timedwait() 重复锁定和解锁信号量。基于示例 here ,我通过以下方式将我的结构 timespec 设置为 20 毫秒超时: sem_t semaphore; /
我正在尝试将一个使用信号量的项目(来自 linux)移植到 Mac OS X 但是一些 posix 信号量没有在 Mac OS X 上实现 我在这个端口打到的一个是 sem_timedwait() 我
我们在 RedHat Enterprise Linux 系统上看到带有 pthreads sem_timedwait 的奇怪行为。它仅在 5.3 及更高版本中出现。 当我们使用 sem_init 在后
我是一名优秀的程序员,十分优秀!