Why sem_post() looks like blocked when using WinAPI and Semaphore to create a program that re-running again and again

77 views Asked by At
#include <iostream>
#include <stdlib.h>
#include <processthreadsapi.h>
#include <Windows.h>
#include <semaphore.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <stdarg.h>
#include <strsafe.h>

void ErrorExit(LPTSTR lpszFunction) 
{ 
    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError(); 

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );

    // Display the error message and exit the process

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
        (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); 
    StringCchPrintf((LPTSTR)lpDisplayBuf, 
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error %d: %s"), 
        lpszFunction, dw, lpMsgBuf); 
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); 

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
    ExitProcess(dw); 
}
typedef struct {
    sem_t edited;
    sem_t sus;
    sem_t running;
} sem_res_sus;

sem_res_sus sem_rs;
int checked = 0;
int isSuspend = 0;
int rollbackPoint = -1;
// producer
DWORD WINAPI thread(LPVOID arg) {
    // edited isSuspend to 1 then can running and then suspended by the process
    sem_wait(&sem_rs.edited);
    sem_post(&sem_rs.sus);
    while(isSuspend);
    sem_post(&sem_rs.running);
    std::cout << "thread resume from sus!"  << std::endl;

    sem_wait(&sem_rs.edited);
    sem_post(&sem_rs.sus);
    while(isSuspend);
    sem_post(&sem_rs.running);
    std::cout << "thread resume from sus again!"  << std::endl;
    return EXIT_SUCCESS;
}

DWORD WINAPI scheduler(LPVOID arg) {
    CONTEXT a[2];
    a[0].ContextFlags = CONTEXT_ALL;
    a[1].ContextFlags = CONTEXT_ALL;
    HANDLE hThread = (HANDLE) arg;
    while(checked < 2) {
        sem_wait(&sem_rs.running);
        isSuspend = 1;
        // edited isSuspend to 1 tell thread can running and then suspended by the process
        sem_post(&sem_rs.edited);

        // The process wait thread to tell him it can be suspended
        sem_wait(&sem_rs.sus);

        if (SuspendThread(hThread) == -1) {
            ErrorExit(TEXT("SuspendThread"));
        }
        if (GetThreadContext(hThread, &a[checked]) == 0) {
            ErrorExit(TEXT("GetThreadContext"));
        }
        if (checked == 1) { // 假设此时发生错误
            // 回退到上一个检查点后,需要记录该次回卷点。
            rollbackPoint = 0;
            if (SetThreadContext(hThread, &a[0]) == 0) {
                ErrorExit(TEXT("SetThreadContext"));
            }
        } else {
            rollbackPoint = -1;
        }
        if(ResumeThread(hThread) == -1) {
            ErrorExit(TEXT("ResumeThread"));
        } else {
            isSuspend = 0;
        }
        checked++;
        if (rollbackPoint != -1) {
            // 若回退了
            checked = rollbackPoint + 1;
            rollbackPoint = -1;
        }
    }
}


int main() {
    sem_init(&sem_rs.edited, 0,  0);
    sem_init(&sem_rs.sus, 0, 0);
    sem_init(&sem_rs.running, 0, 1);
    
    DWORD t;
    std::cout << "start execution" << std::endl;
    HANDLE hThread = CreateThread(
        NULL,
        0,
        thread,
        NULL,
        0,
        &t
    );
    DWORD t_h;
    HANDLE control_hThread = CreateThread(
        NULL,
        0,
        scheduler,
        hThread,
        0,
        &t_h
    );
    WaitForSingleObject(hThread, INFINITE);
    WaitForSingleObject(control_hThread, INFINITE);
    CloseHandle(hThread);
    sem_close(&sem_rs.sus);
    sem_close(&sem_rs.edited);
    return EXIT_SUCCESS;
}

The above is my code. In some random number of rounds, it works fine and print "thread resume from sus!" regularly. But then it will blocked thread blocked at sem_post(&sem_rs.sus); scheduler blocked at sem_wait(&sem_rs.sus) How to solve this issues? Thanks

I am searching for why, but nothing helpful.

0

There are 0 answers