Пример мьютекса в туннеле с одной полосой в Windows - PullRequest
0 голосов
/ 06 июня 2018

Я пытаюсь решить классическую проблему семафора / мьютекса в «однополосном туннеле».Это код, который я написал, но он не работает, и я не могу понять, почему.Теоретически, автомобили, идущие в противоположном направлении, должны пересекаться ТОЛЬКО, если туннель уже используется автомобилями, движущимися в том же направлении, в противном случае они должны ждать, результат должен быть примерно таким:

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 голосов
/ 06 июня 2018

Проблема возникает из-за вашего WaitForSingleObject вызова:

Код возврата: WAIT_ABANDONED 0x00000080L

Указанный объект является объектом мьютекса, который не был освобожден потоком, которому принадлежалобъект мьютекса перед завершением потока-владельца.Право собственности на объект мьютекса предоставляется вызывающему потоку, а состояние мьютекса устанавливается равным unsignaled.

Если мьютекс защищал информацию о постоянном состоянии, вы должны проверить его на согласованность.

Поток 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;
}
...