我已经编写了一个Qt控制台应用程序来试用QSemaphores,并发现了一些奇怪的行为。考虑具有1个资源和两个线程获取和释放单个资源的信号量。伪代码:
QSemaphore sem(1); // init with 1 resource available
thread1()
{
while(1)
{
if ( !sem.tryAquire(1 resource, 1 second timeout) )
{
print "thread1 couldn't get a resource";
}
else
{
sem.release(1);
}
}
}
// basically the same thing
thread2()
{
while(1)
{
if ( !sem.tryAquire(1 resource, 1 second timeout) )
{
print "thread2 couldn't get a resource";
}
else
{
sem.release(1);
}
}
}
似乎很简单,但线程通常无法获得资源。解决这个问题的一种方法是让线程在sem.release(1)
之后暂停一段时间。这告诉我的是release()
成员在当前线程循环到tryAquire()
的顶部并且再次抓取资源之前不允许其他线程在while(1)
中等待访问信号量。
这让我感到惊讶,因为使用QMutex
的类似测试显示了正确的行为...即QMutex::tryLock(timeout)
中挂出的另一个帖子在调用QMutex::unlock()
时会得到正确的通知。
有什么想法吗?
答案 0 :(得分:2)
我目前无法完全测试或找到所有支持链接,但这里有一些观察......
首先,documentation for QSemaphore.tryAcquire表示超时值是毫秒,而不是秒。因此,您的线程只等待1毫秒才能使资源变为空闲。
其次,我记得在某个地方(遗憾的是我不记得在哪里)阅读有关当多个线程试图同时获取相同资源时会发生什么的讨论。虽然行为可能因操作系统和情况而异,但似乎典型的结果是它是一个免费的,没有任何一个线程被赋予比另一个更优先。因此,等待获取资源的线程获得它的机会与刚刚释放它的线程一样多,并且尝试立即重新获取它。我不确定线程的priority setting是否会影响这个。
那么,为什么QSemaphore与QMutex会有不同的结果?好吧,我认为信号量可能是一个更复杂的系统资源,需要更多的时间来获取和释放互斥锁。我最近为互斥体做了一些简单的计时,并发现平均需要大约15-25微秒来锁定或解锁一个。在你的线程等待的1毫秒内,这将是至少20个锁定和解锁周期,并且同一线程总是在该时间内重新获得锁定的几率很小。等待线程可能会在等待的时间内至少在苹果上咬一口,因此在您的示例中使用互斥锁时,您不会看到任何采集失败。
然而,如果释放和获取信号量需要更长时间(我没有计时,但我猜他们可能),那么你很可能只是偶然得到一个线程能够继续重新获取资源,直到等待线程的等待条件用完为止。