Linked Questions

Popular Questions

I am trying to replicate a possible undesired behavior upon calling EnterCriticalSection, caused by doing something bad. Basically, I want to simulate the scenario in which my code hangs indefinitely on EnterCriticalSection, situation that I am experiencing in the production code.

From what I understand from MSDN, this should happen when a thread that is not owning the critical section calls LeaveCriticalSection (https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-leavecriticalsection)

If a thread calls LeaveCriticalSection when it does not have ownership of the specified critical section object, an error occurs that may cause another thread using EnterCriticalSection to wait indefinitely.

I have several questions / experiments in regards to this.

  1. I tried to simulate this scenario, but I am not getting the same indefinite wait on the thread that will call EnterCriticalSection.

Would anyone know why this is the case? I am posting the code below, along with some observations:

#include "pch.h"
#include <iostream>
#include <thread>
#include <Windows.h>

#define N 1

CRITICAL_SECTION CriticalSection;

int shared_resource = -1;

using namespace std;

void foo1(int x) throw()
{
    Sleep(5000);
    cout << "Starting foo1" << endl;

    EnterCriticalSection(&CriticalSection);

    shared_resource = x;

    LeaveCriticalSection(&CriticalSection);

    cout << "Leaving foo1" << endl;
}

void foo2(int x) throw()
{
    cout << "Starting foo2" << endl;

    LeaveCriticalSection(&CriticalSection);

    cout << "Leaving foo2" << endl;
}

int main(void)
{
    InitializeCriticalSection(&CriticalSection);

    cout << "Hello World!" << endl;

    for (int i = 0; i < N; i++)
    {
        thread th1(foo1, 1);
        thread th2(foo2, 2);

        th1.join();
        th2.join();

        cout << "Shared resource: " << shared_resource << endl;
        shared_resource = -1;
    }

    DeleteCriticalSection(&CriticalSection);

    return 0;
}

Something I noted is that when I am in foo2, after LeaveCriticalSection, the CRITICAL_SECTION struct has the following fields:

LockCount -1
RecursionCount -1

This does not seem to interfere with foo1, which is able to just grab the ownership and get inside the critical section, setting the fields to:

LockCount -2
RecursionCount 1

right when it is inside the critical section. (Upon EnterCriticalSection, the fields have the same values as the ones written from foo2). Why is this?

  1. And one more thing. I also tried deleting the critical section from within either of the two critical sections. As per MSDN (https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-deletecriticalsection#remarks), this should cause either Memory Access Violation or undefined behavior for successive calls into EnterCriticalSection or LeaveCriticalSection. So I did something like this, for both foo thread methods:

    void foo2(int x) throw()
    {
         cout << "Starting foo2" << endl;
    
         EnterCriticalSection(&CriticalSection);
    
         shared_resource = x;
         DeleteCriticalSection(&CriticalSection);
    
         LeaveCriticalSection(&CriticalSection);
    
         cout << "Leaving foo2" << endl;
    }
    

This caused the Memory Access Violation exceptions. When I added the throw() specifier, it seemed to start to hang upon EnterCriticalSection on the other thread (the one that didn't delete it yet). But this was not a consistent repro. Sometimes I was still getting Memory Access Violation either on LeaveCriticalSection within the same thread that also deletes it or on EnterCriticalSection on the other thread. What is happening here?

TL;DR: I am trying to make EnterCriticalSection hang. What is the minimum needed in order to accomplish this?

Thanks!

Related Questions