我的作业中有一道题:利用Windows API使用mutex实现线程同步。 我尝试使用两个互斥体来实现此目的,但失败了,因为我发现如果线程没有锁定互斥体本身,则无法使用
ReleaseMutex()
来释放互斥体。那么,是否可以使用两个互斥体来实现线程同步呢?
这是我的代码。 我的代码旨在按顺序打印
Thread A is running
和 Thread B is running
。 IOW,一旦线程 A 打印了一行,下一行应该来自线程 B,一旦线程 B 打印了一行,下一行应该来自线程 A。
像这样:
Thread A is running
Thread B is running
Thread A is running
Thread B is running
...
但它实际上是这样的:
Thread A is running
ReleaseMutex failed. Error: 288
Thread A is running
ReleaseMutex failed. Error: 288
Thread A is running
ReleaseMutex failed. Error: 288
...(Print "Thread A is running ReleaseMutex failed. Error: 288" 10 times, and then block)
在threadA()函数中,
ReleaseMutex(mutexB)
失败,错误:288。此外,WaitForSingleObject(mutexA, INFINITE)
也遇到同样的ERROR:288,但它不会阻塞。相反,它运行 10 次并打印“Thread A is running”。然而,threadB 永远被阻塞了。
请帮我解决这个问题!!!!
是否可以使用两个互斥锁来实现线程同步?
为什么
ReleaseMutex()
会失败?
为什么
WaitForSingleObject(mutex, INFINITE)
不阻塞而是返回一个值?
HANDLE mutexA;
HANDLE mutexB;
unsigned __stdcall threadA(void*) {
for (int i = 0; i < 10; i++) {
WaitForSingleObject(mutexA, INFINITE);
cout << "Thread A is running" << endl;
if (!ReleaseMutex(mutexB)) {
cout << "ReleaseMutex failed. Error: " << GetLastError() << endl;
}
}
return 0;
}
unsigned __stdcall threadB(void*) {
for (int i = 0; i < 10; i++) {
WaitForSingleObject(mutexB, INFINITE);
cout << "Thread B is running" << endl;
if (!ReleaseMutex(mutexA)) {
cout << "ReleaseMutex failed. Error: " << GetLastError() << endl;
}
}
return 0;
}
int main() {
unsigned threadID1, threadID2;
mutexA = CreateMutex(nullptr, FALSE, nullptr);// Initialize the mutex and by default
mutexB = CreateMutex(nullptr, TRUE, nullptr);// Initialize the mutex and lock it immediately
auto hThreadA = (HANDLE)_beginthreadex(nullptr, 0, threadA, nullptr, 0, &threadID1);
auto hThreadB = (HANDLE)_beginthreadex(nullptr, 0, threadB, nullptr, 0, &threadID2);
WaitForSingleObject(hThreadA, INFINITE);
WaitForSingleObject(hThreadB, INFINITE);
CloseHandle(hThreadA);
CloseHandle(hThreadB);
CloseHandle(mutexA);
CloseHandle(mutexB);
return 0;
}
只有拥有互斥锁的线程才能释放它。 您尝试做的事情可以通过互斥体来完成,但不能以您尝试的方式完成。 尝试更多类似这样的事情:
HANDLE mutex;
char whichThread;
unsigned __stdcall threadA(void*) {
for (int i = 0; i < 10; i++) {
do {
WaitForSingleObject(mutex, INFINITE);
if (whichThread != 'A') {
ReleaseMutex(mutex);
Sleep(0);
continue;
}
} while (true);
cout << "Thread A is running" << endl;
whichThread = 'B';
ReleaseMutex(mutex);
}
return 0;
}
unsigned __stdcall threadB(void*) {
for (int i = 0; i < 10; i++) {
do {
WaitForSingleObject(mutex, INFINITE);
if (whichThread != 'B') {
ReleaseMutex(mutex);
Sleep(0);
continue;
}
} while (true);
cout << "Thread B is running" << endl;
whichThread = 'A';
ReleaseMutex(mutex);
}
return 0;
}
int main() {
mutex = CreateMutex(nullptr, FALSE, nullptr);
whichThread = 'A';
unsigned threadID1, threadID2;
auto hThreadA = (HANDLE) _beginthreadex(nullptr, 0, threadA, nullptr, 0, &threadID1);
auto hThreadB = (HANDLE) _beginthreadex(nullptr, 0, threadB, nullptr, 0, &threadID2);
WaitForSingleObject(hThreadA, INFINITE);
WaitForSingleObject(hThreadB, INFINITE);
CloseHandle(hThreadA);
CloseHandle(hThreadB);
CloseHandle(mutex);
return 0;
}
话虽这么说,我建议使用 Condition Variables 或 Event Objects 代替,例如:
CRITICAL_SECTION critSec;
CONDITION_VARIABLE condVarA, condVarB;
char whichThread;
unsigned __stdcall threadA(void*) {
for (int i = 0; i < 10; i++) {
EnterCriticalSection(&critSec);
while (whichThread != 'A') {
SleepConditionVariableCS(&condVarB, &critSec, INFINITE);
}
cout << "Thread A is running" << endl;
whichThread = 'B';
LeaveCriticalSection(&critSec);
WakeConditionVariable(&condVarA);
}
return 0;
}
unsigned __stdcall threadB(void*) {
for (int i = 0; i < 10; i++) {
EnterCriticalSection(&critSec);
while (whichThread != 'B') {
SleepConditionVariableCS(&condVarA, &critSec, INFINITE);
}
cout << "Thread B is running" << endl;
whichThread = 'A';
LeaveCriticalSection(&critSec);
WakeConditionVariable(&condVarB);
}
return 0;
}
int main() {
InitializeCriticalSection(&critSec);
InitializeConditionVariable(&condVarA);
InitializeConditionVariable(&condVarB);
whichThread = 'A';
unsigned threadID1, threadID2;
auto hThreadA = (HANDLE) _beginthreadex(nullptr, 0, threadA, nullptr, 0, &threadID1);
auto hThreadB = (HANDLE) _beginthreadex(nullptr, 0, threadB, nullptr, 0, &threadID2);
WaitForSingleObject(hThreadA, INFINITE);
WaitForSingleObject(hThreadB, INFINITE);
CloseHandle(hThreadA);
CloseHandle(hThreadB);
DeleteCriticalSection(&critSecA);
DeleteCriticalSection(&critSecB);
return 0;
}
HANDLE hEventA, hEventB;
unsigned __stdcall threadA(void*) {
for (int i = 0; i < 10; i++) {
WaitForSingleObject(hEventB, INFINITE);
cout << "Thread A is running" << endl;
SetEvent(hEventA);
}
return 0;
}
unsigned __stdcall threadB(void*) {
for (int i = 0; i < 10; i++) {
WaitForSingleObject(hEventA, INFINITE);
cout << "Thread B is running" << endl;
SetEvent(hEventB);
}
return 0;
}
int main() {
hEventA = CreateEvent(nullptr, FALSE, FALSE, nullptr);
hEventB = CreateEvent(nullptr, FALSE, TRUE, nullptr);
unsigned threadID1, threadID2;
auto hThreadA = (HANDLE) _beginthreadex(nullptr, 0, threadA, nullptr, 0, &threadID1);
auto hThreadB = (HANDLE) _beginthreadex(nullptr, 0, threadB, nullptr, 0, &threadID2);
WaitForSingleObject(hThreadA, INFINITE);
WaitForSingleObject(hThreadB, INFINITE);
CloseHandle(hThreadA);
CloseHandle(hThreadB);
CloseHandle(hEventA);
CloseHandle(hEventB);
return 0;
}