none
Can we use CriticalSection synchronization mechanism without using threads? RRS feed

  • Question

  • Hi All,            

    My understanding about CriticalSection is - Using Critical Section one thread will lock the resource (area of code). Once the thread has performed it's action, it releases the resource so that other thread can lock the resource.

    But in the below scenario, By calling one function from other functions, without using the threads we are using critical section and locking the resource. 

    As a beginner, i am wondering and wanted to know that, Can we use synchronization techniques to lock the resources without using the threads?

    And here in my scenario when the application is launching we are calling the function which has CriticalSection. And also from OnTimer() function for each second we are calling the Criticalsection function.

    Below is the code snippet:

    In EventGenerator.cpp file

    From the below ::InitUPS() function, we are calling ::CreateUPSControl() which has implemented with Critical Section.
    InitUPS() function is calling when launching the application.

    ErrCode CEventGenerator::InitUPS()
    {
        //This function should only be called once on startup
        bool bHadUPS = (theUPSControl != NULL);
        ErrCode err = ERR_SUCCESS;

        if (bHadUPS == false)
        {
            err = CreateUPSControl();
        }

        return(err);
    }

    And from below function also we are calling ::CreateUPSControl() function.

    GetUPSEvents() function is calling from the OnTimer() function

    ErrCode CEventGenerator::GetUPSEvents (CEvents * anEventsPtr)
    {
        DWORD   bRequiredUsages;
        bool    bHadUPS = (theUPSControl != NULL);
        bool    bHaveUPSNow = false;
        ErrCode err = ERR_SUCCESS;
        long    bHadAC = 1;

        assert(anEventsPtr != NULL);

        if (theUPSControl == NULL)
        {
            err = CreateUPSControl();
        }

        if (err == ERR_SUCCESS)
        {

            err = theCurrentData.GetFrom(theUPSControl);

            if (err == ERR_SUCCESS)
            {
                theIsCurrentDataFilled = true;
                bHaveUPSNow = true;
            }
            else
            {
                EnterCriticalSection(&theControlCritSect);
                delete theUPSControl;
                theUPSControl = NULL;
                LeaveCriticalSection(&theControlCritSect);

                if (thePreviousData.theACPresent)
                {
                    bHadAC = *thePreviousData.theACPresent;
                }

                thePreviousData.ClearUp();
                theCurrentData.ClearUp();
            }
        }


        EnterCriticalSection(&theDataCritSect);

        theHaveWeGotComms = (err == ERR_SUCCESS);

        // Only bother updating theSafeData if we've got comms (if not, data is probably garbage anyhow)
        if (theHaveWeGotComms)
        {
            if (theIsCurrentDataFilled == true)
            {
                theSafeData = theCurrentData;
            }
            else
            {
                theSafeData = thePreviousData;
            }
        }
        else
        {
            theSafeData.ClearUp();
        }

        LeaveCriticalSection(&theDataCritSect);

        *anEventsPtr = theEvents;
        theEvents.ClearAllEvents();

        return err;
    }

    Below is the function where we are using CriticalSection.

    ErrCode CEventGenerator::CreateUPSControl()
    {
        CUPSControl * ctl = NULL;
        long vendorID = APCVENDORID;

        ErrCode retErr = CUPSControl::CreateNewUPSControl(&ctl, 0, vendorID);

        std::auto_ptr<CUPSControl> destroyer(ctl);

        if (retErr == ERR_SUCCESS)
        {
            assert(ctl != NULL);

            retErr = thePreviousData.GetFrom(ctl);

            ::EnterCriticalSection(&theDataCritSect); 
            theSafeData = thePreviousData;          
            ::LeaveCriticalSection(&theDataCritSect); 

            if (retErr == ERR_SUCCESS)
            {
                CheckForInitialEvents(thePreviousData);
                ::EnterCriticalSection(&theControlCritSect);
                delete theUPSControl;
                theUPSControl = destroyer.release();
                ::LeaveCriticalSection(&theControlCritSect);
            }
            else
            {
                thePreviousData.ClearUp();
                theCurrentData.ClearUp();
            }
        }

        return retErr;
    }

    Friday, June 14, 2019 6:38 AM

Answers

  • The thing to remember about using any synchronisation without the need for it is that it will result in slower code.

    Any synchronisation method has a cost. There is the obvious space cost for the synchronisation object and there is the time cost for the constant obtaining the object and releasing the object. This can be quite a significant performance drain.

    It is possible for some APIs to give you a choice, for example Direct3D 11 has the D3D11_CREATE_DEVICE_FLAG D3D11_CREATE_DEVICE_SINGLETHREADED. This flag is there so that if you only ever use the Direct3D objects from a single thread, you can get better performance because it will not do things in a thread safe manner. Direct2D also has the D2D1_FACTORY_TYPE enumeration which gives you the choice in Direct2D for the same reason.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Friday, June 14, 2019 1:45 PM
  • Hi,

    Thank you for posting here.

    >>Can we use CriticalSection synchronization mechanism without using threads?

    Accorsing to you case I wonder what do you mean "without using threads", if you want to lock the resources without using Mutex Locks? If so , As far as I'm concerned you could. Critical Section is a more rigorous means of synchronization than mutex locks.

    A critical section object provides synchronization similar to that provided by a mutex object, except that a critical section can be used only by the threads of a single process. Critical section objects cannot be shared across processes.

    Event, mutex, and semaphore objects can also be used in a single-process application, but critical section objects provide a slightly faster, more efficient mechanism for mutual-exclusion synchronization . Like a mutex object, a critical section object can be owned by only one thread at a time, which makes it useful for protecting a shared resource from simultaneous access. Unlike a mutex object, there is no way to tell whether a critical section has been abandoned.

    I suggest you could refer to the links :
    https://docs.microsoft.com/en-us/windows/desktop/sync/critical-section-objects
    https://github.com/angrave/SystemProgramming/wiki/Synchronization,-Part-4:-The-Critical-Section-Problem
    https://docs.microsoft.com/en-us/windows/desktop/sync/using-critical-section-objects

    Best Regards,

    Jeanine Zhang

    Friday, June 14, 2019 8:43 AM
    Moderator

All replies

  • Hi,

    Thank you for posting here.

    >>Can we use CriticalSection synchronization mechanism without using threads?

    Accorsing to you case I wonder what do you mean "without using threads", if you want to lock the resources without using Mutex Locks? If so , As far as I'm concerned you could. Critical Section is a more rigorous means of synchronization than mutex locks.

    A critical section object provides synchronization similar to that provided by a mutex object, except that a critical section can be used only by the threads of a single process. Critical section objects cannot be shared across processes.

    Event, mutex, and semaphore objects can also be used in a single-process application, but critical section objects provide a slightly faster, more efficient mechanism for mutual-exclusion synchronization . Like a mutex object, a critical section object can be owned by only one thread at a time, which makes it useful for protecting a shared resource from simultaneous access. Unlike a mutex object, there is no way to tell whether a critical section has been abandoned.

    I suggest you could refer to the links :
    https://docs.microsoft.com/en-us/windows/desktop/sync/critical-section-objects
    https://github.com/angrave/SystemProgramming/wiki/Synchronization,-Part-4:-The-Critical-Section-Problem
    https://docs.microsoft.com/en-us/windows/desktop/sync/using-critical-section-objects

    Best Regards,

    Jeanine Zhang

    Friday, June 14, 2019 8:43 AM
    Moderator
  • The reason to use a critical section is to provide thread-safe access to a resource.  If your resource is only accessed by a single thread then the synchronization provided by using a critical section would be unnecessary since no other thread would be contending for access to the resource.

    • Edited by RLWA32 Friday, June 14, 2019 9:20 AM
    Friday, June 14, 2019 9:19 AM
  • The thing to remember about using any synchronisation without the need for it is that it will result in slower code.

    Any synchronisation method has a cost. There is the obvious space cost for the synchronisation object and there is the time cost for the constant obtaining the object and releasing the object. This can be quite a significant performance drain.

    It is possible for some APIs to give you a choice, for example Direct3D 11 has the D3D11_CREATE_DEVICE_FLAG D3D11_CREATE_DEVICE_SINGLETHREADED. This flag is there so that if you only ever use the Direct3D objects from a single thread, you can get better performance because it will not do things in a thread safe manner. Direct2D also has the D2D1_FACTORY_TYPE enumeration which gives you the choice in Direct2D for the same reason.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Friday, June 14, 2019 1:45 PM