让我们假装没有为C ++提供信号量的库。我写了这个:
#include <vector>
#include <Windows.h>
class Semaphore {
HANDLE mutexS; // provides mutex in semaphore rutines
std::vector<HANDLE> queue; // provides FIFO queue for blocked threads
int value; // semaphore's value
public:
Semaphore(int init=1);
~Semaphore();
void wait();
void signal();
};
Semaphore::Semaphore(int init) {
value = init;
queue = std::vector<HANDLE>();
mutexS = CreateMutex(0,0,0);
}
Semaphore::~Semaphore() {
CloseHandle(mutexS);
}
void Semaphore::signal() {
WaitForSingleObject(mutexS, INFINITE);
if (++value <= 0) {
HANDLE someOldThread = queue.front();
ResumeThread(someOldThread);
queue.erase(queue.begin());
CloseHandle(someOldThread);
}
ReleaseMutex(mutexS);
}
我想知道为什么wait()的实现不起作用:
void Semaphore::wait() {
WaitForSingleObject(mutexS, INFINITE);
if (--value < 0) {
HANDLE thisThread = GetCurrentThread();
queue.push_back(thisThread);
ReleaseMutex(mutexS);
SuspendThread(thisThread );
}
else
ReleaseMutex(mutexS);
}
这个有效:
void Semaphore::wait() {
WaitForSingleObject(mutexS, INFINITE);
if (--value < 0) {
HANDLE thisThread = GetCurrentThread();
HANDLE alsoThisThread;
DuplicateHandle(GetCurrentProcess(), thisThread, GetCurrentProcess(), &alsoThisThread, 0, 0, DUPLICATE_SAME_ACCESS);
queue.push_back(alsoThisThread);
ReleaseMutex(mutexS);
SuspendThread(alsoThisThread);
}
else
ReleaseMutex(mutexS);
}
每种情况究竟发生了什么?我已经在很长一段时间里一直在敲打它。 wait的第一个实现,它不起作用,使我的程序块(好吧,它可能永远阻止一些线程)。第二个实现就像一个魅力。是什么赋予了 ?为什么我需要复制线程句柄并阻止重复?
答案 0 :(得分:1)
MSDN在这里有很多帮助;)
GetCurrentThread返回一个伪句柄,它是&#34;当前线程的常量&#34;:
伪句柄是一个特殊的常量,被解释为当前的线程句柄。
因此,当你在队列中推送它时,你总是推动一个常量,表示&#34;当前线程&#34;,这显然不是你想要的。
要获得真正的处理,您必须使用DuplicateHandle
如果hSourceHandle是GetCurrentProcess或GetCurrentThread返回的伪句柄,则DuplicateHandle将其转换为进程或线程的实际句柄。
最后一点:我想你正在实施这个&#34;测试&#34;对?因为有几个潜在的问题..一个非常好的学习练习就是挖掘它们。但是你不应该在生产代码中使用它。
出于好奇:如果你想要多一点实验,那么&#34;规范&#34;使用互斥锁实现信号量的方法是使用两个互斥量:see here
答案 1 :(得分:0)
MSDN documentation for GetCurrentThread有答案(口音是我的):
返回值是当前线程的伪句柄。
伪句柄是一个特殊的常量,被解释为当前的线程句柄。无论何时需要线程句柄,调用线程都可以使用此句柄来指定自己。
...
一个线程不能使用该函数来创建一个句柄,其他线程可以使用该句柄来引用第一个线程。 句柄始终被解释为引用正在使用它的线程。一个线程可以创建一个真正的&#34;通过在调用DuplicateHandle函数时将伪句柄指定为源句柄来处理其他线程可以使用或由其他进程继承的自身。