c windows

时间:2018-06-06 10:10:37

标签: c windows mutex semaphore critical-section

我试图解决经典的单线隧道"信号量/互斥问题。 这是我写的代码,但它不起作用,我无法理解为什么。 从理论上讲,如果隧道已经被同一方向的汽车使用,那么来自相反方向的汽车应该交叉,否则他们应该等待,输出应该是这样的:

car1_leftToRight crossing
car2_leftToRight crossing
car1_leftToRight end crossing
car2_leftToRight end crossing  (ALL cars leftToRight have crossed)
car1_rightToLeft start crossing 
etc..

但是我当前的输出是您在我附加的图像中可以看到的输出。 我还创建了一个全局变量(globalCarsCrossing)来跟踪目前有多少辆汽车正在过桥,你可以看到来自相反方向的汽车似乎正在同时穿越! enter image description here

你对我做错了什么有什么建议吗?

#define UNICODE
#define _UNICODE
#define _CRT_SECURE_NO_WARNINGS

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <WinBase.h>
#include <process.h> //include for function _beginthreadex

int globalCarsCrossing = 0;

typedef struct {
    int numTraversingCar;
    int crossingTime;
    int arrivalTime; //0 - arrivalTime -> random number, how much time pass between cars arrival
    HANDLE mutex;
    LPHANDLE bridgeMutexPtr;
    int direction;
} ThParams;

DWORD WINAPI thFunction(LPVOID thParamsPtr);
void crossBridge();

int _tmain(int argc, LPTSTR argv[])
{
    int timeL2R, timeR2L, timeARRIVAL, nL2R, nR2L;
    LPHANDLE thL2Rarray, thR2Larray;
    ThParams paramsL2R, paramsR2L;
    HANDLE bridgeMutex;

    if (argc < 6) 
    {
        _ftprintf(stderr, _T("missing parameters: <timeL2R> <timeR2L> <timeARRIVAL> <nL2R> <nR2L>\n"));
        exit(EXIT_FAILURE);
    }

    timeL2R = _ttoi(argv[1]); //WINDOWS version of "atoi"
    timeR2L = _ttoi(argv[2]);
    timeARRIVAL = _ttoi(argv[3]);
    nL2R = _ttoi(argv[4]);
    nR2L = _ttoi(argv[5]);

    //allocates all threads array
    thL2Rarray = (LPHANDLE)malloc(nL2R * sizeof(HANDLE));
    thR2Larray = (LPHANDLE)malloc(nR2L * sizeof(HANDLE));

    //initialize all parameters
    bridgeMutex = CreateMutex(NULL, FALSE, NULL);

    //create structs for threads
    paramsL2R.mutex = CreateMutex(NULL, FALSE, NULL);
    paramsL2R.bridgeMutexPtr = &bridgeMutex;
    paramsL2R.arrivalTime = timeARRIVAL;
    paramsL2R.numTraversingCar = 0;
    paramsL2R.crossingTime = timeL2R;
    paramsL2R.direction = 0;

    //paramsR2L.criticalSectionPtr = &criticalSectionR2L;
    paramsR2L.mutex = CreateMutex(NULL, FALSE, NULL);
    paramsR2L.bridgeMutexPtr = &bridgeMutex;
    paramsR2L.arrivalTime = timeARRIVAL;
    paramsR2L.numTraversingCar = 0;
    paramsR2L.crossingTime = timeR2L;
    paramsR2L.direction = 1;

    //create L2R threads 
    for (int i = 0; i<nL2R; i++)
        thL2Rarray[i] = CreateThread(NULL, 0, thFunction, &paramsL2R, 0, NULL);
    //create R2L threads 
    for (int i = 0; i<nR2L; i++)
        thR2Larray[i] = CreateThread(NULL, 0, thFunction, &paramsR2L, 0, NULL);

    //wait for ALL threads to return
    WaitForMultipleObjects(nL2R, thL2Rarray, TRUE, INFINITE);
    WaitForMultipleObjects(nR2L, thR2Larray, TRUE, INFINITE);
    _tprintf(_T("all threads are returned\n"));

    //closa all thread handle
    for (int i = 0; i<nL2R; i++)
        CloseHandle(thL2Rarray[i]);
    for (int i = 0; i<nR2L; i++)
        CloseHandle(thR2Larray[i]);

    ////free and release everything
    free(thL2Rarray);
    free(thR2Larray);
    CloseHandle(bridgeMutex);
    CloseHandle(paramsR2L.mutex);
    CloseHandle(paramsL2R.mutex);

    return 0;
}

DWORD WINAPI thFunction(LPVOID thParamsPtr)
{
    ThParams *paramsPtr = (ThParams *)thParamsPtr;

    WaitForSingleObject(paramsPtr->mutex, INFINITE);
        paramsPtr->numTraversingCar = paramsPtr->numTraversingCar + 1;

        if (paramsPtr->numTraversingCar == 1)
            WaitForSingleObject(*(paramsPtr->bridgeMutexPtr), INFINITE);

        globalCarsCrossing++;
        _tprintf(_T("%d crossing direction: %d, TOT_cars_from_this_direction: %d,  GLOBAL_CARS_CROSSING: %d\n"), GetCurrentThreadId(), paramsPtr->direction, paramsPtr->numTraversingCar, globalCarsCrossing);
    ReleaseMutex(paramsPtr->mutex);

    crossBridge();

    WaitForSingleObject(paramsPtr->mutex, INFINITE);
        paramsPtr->numTraversingCar = paramsPtr->numTraversingCar - 1;
        globalCarsCrossing--;
        _tprintf(_T("%d end crossing direction: %d, TOT_cars_from_this_direction: %d,  GLOBAL_CARS_CROSSING %d\n"), GetCurrentThreadId(), paramsPtr->direction, paramsPtr->numTraversingCar, globalCarsCrossing);
        if (paramsPtr->numTraversingCar == 0) {
            _tprintf(_T("RELEASED\n"));
            ReleaseMutex(*(paramsPtr->bridgeMutexPtr));
        }
    ReleaseMutex(paramsPtr->mutex);

    return 0;
}

1 个答案:

答案 0 :(得分:1)

问题来自您的WaitForSingleObject电话:

  

返回代码:WAIT_ABANDONED 0x00000080L

     

指定的对象是在拥有线程终止之前由拥有互斥对象的线程未释放的互斥对象。互斥对象的所有权被授予调用线程,并且互斥锁状态被设置为无信号。

     

如果互斥锁正在保护持久状态信息,则应检查它是否一致。

线程2944在隧道上获得互斥锁,使其车辆交叉并完成,而不释放互斥锁。

当线程3560调用WaitForSingleObject时,此函数返回WAIT_ABANDONED

您的代码无法执行您想要的操作,因为线程所使用的互斥锁必须由同一个线程发布

信号量更适合锁定隧道。

编辑:

我首先发帖建议使用CriticalSection,但与Mutex一样,必须获取CriticalSection并由同一个帖子发布。

示例实施:

#define UNICODE
#define _UNICODE
#define _CRT_SECURE_NO_WARNINGS

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <WinBase.h>
#include <process.h> //include for function _beginthreadex

int globalCarsCrossing = 0;

typedef struct {
    int numTraversingCar;
    int crossingTime;
    int arrivalTime; //0 - arrivalTime -> random number, how much time pass between cars arrival
    HANDLE mutex;
    HANDLE bridgeSem;
    int direction;
} ThParams;

DWORD WINAPI thFunction(LPVOID thParamsPtr);
void crossBridge();

int _tmain(int argc, LPTSTR argv[])
{
    int timeL2R, timeR2L, timeARRIVAL, nL2R, nR2L;
    LPHANDLE thL2Rarray, thR2Larray;
    ThParams paramsL2R, paramsR2L;
    HANDLE bridgeSem;

    if (argc < 6) 
    {
        _ftprintf(stderr, _T("missing parameters: <timeL2R> <timeR2L> <timeARRIVAL> <nL2R> <nR2L>\n"));
        exit(EXIT_FAILURE);
    }

    timeL2R = _ttoi(argv[1]); //WINDOWS version of "atoi"
    timeR2L = _ttoi(argv[2]);
    timeARRIVAL = _ttoi(argv[3]);
    nL2R = _ttoi(argv[4]);
    nR2L = _ttoi(argv[5]);

    //allocates all threads array
    thL2Rarray = (LPHANDLE)malloc(nL2R * sizeof(HANDLE));
    thR2Larray = (LPHANDLE)malloc(nR2L * sizeof(HANDLE));

    //initialize all parameters
    bridgeSem = CreateSemaphore(NULL, 1, 1, NULL);

    //create structs for threads
    paramsL2R.mutex = CreateMutex(NULL, FALSE, NULL);
    paramsL2R.bridgeSem = bridgeSem;
    paramsL2R.arrivalTime = timeARRIVAL;
    paramsL2R.numTraversingCar = 0;
    paramsL2R.crossingTime = timeL2R;
    paramsL2R.direction = 0;

    //paramsR2L.criticalSectionPtr = &criticalSectionR2L;
    paramsR2L.mutex = CreateMutex(NULL, FALSE, NULL);
    paramsR2L.bridgeSem = bridgeSem;
    paramsR2L.arrivalTime = timeARRIVAL;
    paramsR2L.numTraversingCar = 0;
    paramsR2L.crossingTime = timeR2L;
    paramsR2L.direction = 1;

    //create L2R threads 
    for (int i = 0; i<nL2R; i++)
        thL2Rarray[i] = CreateThread(NULL, 0, thFunction, &paramsL2R, 0, NULL);
    //create R2L threads 
    for (int i = 0; i<nR2L; i++)
        thR2Larray[i] = CreateThread(NULL, 0, thFunction, &paramsR2L, 0, NULL);

    //wait for ALL threads to return
    WaitForMultipleObjects(nL2R, thL2Rarray, TRUE, INFINITE);
    WaitForMultipleObjects(nR2L, thR2Larray, TRUE, INFINITE);
    _tprintf(_T("all threads are returned\n"));

    //closa all thread handle
    for (int i = 0; i<nL2R; i++)
        CloseHandle(thL2Rarray[i]);
    for (int i = 0; i<nR2L; i++)
        CloseHandle(thR2Larray[i]);

    ////free and release everything
    free(thL2Rarray);
    free(thR2Larray);
    CloseHandle(bridgeSem);
    CloseHandle(paramsR2L.mutex);
    CloseHandle(paramsL2R.mutex);

    return 0;
}

DWORD WINAPI thFunction(LPVOID thParamsPtr)
{
    ThParams *paramsPtr = (ThParams *)thParamsPtr;

    WaitForSingleObject(paramsPtr->mutex, INFINITE);
        paramsPtr->numTraversingCar = paramsPtr->numTraversingCar + 1;

        if (paramsPtr->numTraversingCar == 1)
            WaitForSingleObject(paramsPtr->bridgeSem, INFINITE);

        globalCarsCrossing++;
        _tprintf(_T("%d crossing direction: %d, TOT_cars_from_this_direction: %d,  GLOBAL_CARS_CROSSING: %d\n"), GetCurrentThreadId(), paramsPtr->direction, paramsPtr->numTraversingCar, globalCarsCrossing);
    ReleaseMutex(paramsPtr->mutex);

    crossBridge();

    WaitForSingleObject(paramsPtr->mutex, INFINITE);
        paramsPtr->numTraversingCar = paramsPtr->numTraversingCar - 1;
        globalCarsCrossing--;
        _tprintf(_T("%d end crossing direction: %d, TOT_cars_from_this_direction: %d,  GLOBAL_CARS_CROSSING %d\n"), GetCurrentThreadId(), paramsPtr->direction, paramsPtr->numTraversingCar, globalCarsCrossing);
        if (paramsPtr->numTraversingCar == 0) {
            _tprintf(_T("RELEASED\n"));
            ReleaseSemaphore(paramsPtr->bridgeSem, 1, NULL);
        }
    ReleaseMutex(paramsPtr->mutex);

    return 0;
}