我不希望该函数被多个线程同时输入,我也不希望它尚未返回时再次输入。有什么方法可以实现我的目标吗?非常感谢!
7 回答
这两个目标都可以通过互斥信号量来实现。
正如其他答案所解释的那样,在一个线程上进行时阻止其他线程进入该函数非常简单。但是如果你想让它在它已经被输入时阻塞在同一个线程中......好吧,那是一个死锁。
使用临界区(InitializeCriticalSection()、EnterCriticalSection()、LeaveCriticalSection())并实现一个入口计数器。临界区将防止来自不同线程的重新进入,而入口计数器将防止来自同一线程的重新进入。
要实现条目计数器,请使用公共变量(您的情况为布尔值)和括号类。一旦你已经进入临界区(因此没有其他线程将并行执行相同的代码)检查变量的值。如果它声明该函数已被输入 - 离开(首先释放关键部分,然后离开该函数)。否则,构造将更改变量值的括号类实例。所以下次这个线程进入函数时,它会检查变量,看到重新进入已经发生并离开。离开函数后,括号类的析构函数会将变量更改为其原始值。
对临界区条目和条目计数器更改使用括号类是明智的,这样您的代码是异常安全的,并且所有操作都按必要的顺序执行,无论您如何离开函数 - 在异常或返回语句时。
f will only be called runs only, when nobody else is currently running it. (This is concept demonstration with only Win32 calls)
void f();
err call_f()
{
static HMUTEX hMutex;
if( !hMutex )
{
hMutex = ::CreateMutex( 0, TRUE, 0 );
}
else
{
if( WaitForSingleObject( hMutex, 0 ) != WAIT_OBJECT_0 )
return ERR_ALREADY_RUNNING;
}
// calling f here
f();
ReleaseMutex( hMutex );
return S_OK;
}
Beware the minimal checking, the missing cleanup code for the mutex and the race-condition on first enter.
既然您说的是 C++ 和 Windows,请查看关键部分。不过,为了便于使用,您可能希望将其包装在几个 C++ 类中。
如果锁已经被占用,关键部分会尝试短时间的自旋循环。对于较短的代码,这通常可以避免完全阻塞等待,从而避免用户<>内核模式等的开销。
通常您需要引入一个监视器,例如在Java 中通过将“同步”关键字添加到您的方法签名中。
(我对吗?)
你可以这样做:
int some_shared_var = 0;
...
for (;some_shared_var != rank;) ;
run_my_function();
some_shared_var++;
rank 是您的线程号(假设您有编号为 0 到 size-1 的线程)。
这只是一个例子。真正的实现会有所不同。这取决于您要使用哪些库/函数来并行化代码(fork、MPI 等)。但我希望它能给你一些有用的想法。