我正在寻找一种方法来确保线程在每次锁定特定资源时都会在特定时间段(如果尚未释放资源)之后强制释放该资源。在需要限制任何特定线程可以拥有该连接的时间量的地方构想一个连接。
我设想这是可以使用的方式:
{
std::lock_guard<std::TimeLimitedMutex> lock(this->myTimeLimitedMutex, timeout);
try {
// perform some operation with the resource that myTimeLimitedMutex guards.
}
catch (MutexTimeoutException ex) {
// perform cleanup
}
}
我看到有一个timed_mutex,如果无法获取锁,该超时会使程序超时。我需要在获取锁后 发生超时。
在某些情况下,您获得的资源可能会被意外拿走。例如,一个tcp套接字-建立套接字连接后,每一侧的代码都需要处理另一侧断开连接的情况。
我正在寻找一种模式,该模式可以处理通常会自行超时的资源类型,但是如果资源超时,则需要将其重置。这不必处理每种类型的资源。
答案 0 :(得分:33)
这是行不通的,它将永远行不通。换句话说,这永远不可能做到。它违背了所有权和原子交易的所有概念。因为当线程获取锁并连续实现两个事务时,它希望它们对于外部单词是原子可见的。在这种情况下,很有可能会破坏交易-将执行交易的第一部分,而不会执行第二部分。
更糟糕的是,由于将强制删除锁,因此在中断的线程有任何回滚机会之前,外部单词可以看到部分执行的事务。
这个想法与所有多线程思维流派相反。
答案 1 :(得分:15)
我支持SergeyAs答案。超时后释放锁定的互斥锁是一个坏主意,无法正常工作。 Mutex代表互斥,这是一个坚不可摧的合同,不能被违反。
但是您可以做您想做的事情:
问题::您想保证线程保持互斥对象的时间不超过特定时间T。
解决方案:永远不要将互斥锁锁定超过时间T。而是编写代码,使互斥锁仅在绝对必要的操作时才被锁定。总是可以给出这样的时间T(当然,考虑到我的多任务和多用户操作系统,对不确定性和限制取模)。
要实现这一点(示例):
这些规则也有例外,但是一般准则是:
(*)这些只是操作的示例,在这些操作中,他们很想锁定整个列表,执行这些操作然后解锁该列表。取而代之的是,建议仅获取列表的本地副本并在互斥锁锁定时清除原始列表,最好使用大多数STL容器提供的swap()
操作。然后对关键部分之外的本地副本执行慢速操作。这并非总是可能,但始终值得考虑。在最坏的情况下,排序具有平方复杂度,通常需要随机访问整个列表。在关键部分之外对列表进行排序(副本)很有用,以后再检查是否需要添加或删除元素。内存分配还具有相当大的复杂性,因此应避免大量的内存分配/取消分配。
答案 2 :(得分:5)
仅使用C ++不能做到这一点。
如果您使用的是Posix系统,则可以完成。
您将必须触发SIGALARM信号,该信号仅在将要超时的线程中未屏蔽。在信号处理程序中,您必须设置一个标志并使用longjmp
返回到线程代码。
在线程代码的setjmp
位置上,只有在信号被触发的情况下才能调用您,因此可以引发Timeout
异常。
有关操作方法,请参见this answer。
此外,在Linux上,您可以直接从信号处理程序中抛出seems(因此这里没有longjmp / setjmp)。
顺便说一句,如果我是你,我会写相反的代码。想想看:您想告诉一个线程“嘿,您花费的时间太长了,所以让我们扔掉到目前为止已经完成的所有(长期)工作,以便我可以取得进展”。 理想情况下,您应该使长线程更加协作,例如执行“我已经完成ABCD任务的A,让我们释放互斥锁,以便其他对象可以在A上进行。然后让我们检查是否可以再次使用它来做B和等等。” 您可能希望粒度更细(在较小的对象上具有更多的互斥量,但请确保按相同的顺序锁定)或使用RW锁(以便其他线程可以在不修改对象的情况下使用这些对象),等等
答案 3 :(得分:1)
这种方法无法执行,因为互斥量的持有者需要机会清除在交易过程中部分处于无效状态的所有内容。这可能会花费未知的任意时间。
典型的方法是在执行长任务时释放锁,然后根据需要重新获取。您必须自己解决这个问题,因为每个人的方法都会稍有不同。
我所知道的唯一接受这种情况的情况是在内核级别,尤其是在微控制器(根据您的要求而定,它们没有内核或全部是内核)方面。您可以设置一个中断来修改调用堆栈,以便在触发该调用时可以取消您感兴趣的特定操作。
答案 4 :(得分:0)
“条件”变量可能会超时。这使您可以等待直到线程自愿释放资源(使用notify_one()或notify_all()),但是等待本身将在指定的固定时间后超时。
Examples in the Boost documentation for "conditions"可能会更清楚。
如果要强制发布,则必须编写代码以强制发布。这可能很危险。用C ++编写的代码可以完成一些非常接近金属的工作。该资源可能正在访问真实的硬件,并且可能正在等待完成某件事。无论程序停留在什么位置,都可能无法实际结束。
但是,如果可能的话,您可以在wait()超时的线程中处理它。