Windows API可以使用两个互斥体来实现线程同步吗?

问题描述 投票:0回答:1

我的作业中有一道题:利用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;
}
c++ windows winapi thread-synchronization
1个回答
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 VariablesEvent 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;
}
© www.soinside.com 2019 - 2024. All rights reserved.