locked
How to handle the situation where shared data (shared memory) using raw pointers being used in two separate threads in C++? RRS feed

  • Question

  • Hello All,

    Could someone please help me, how to handle the situation where the same shared data (shared memory) using raw pointers being used in two separate threads?

    Below is the code snippet and the detailed explanation of the scenario:

    Here in the below function, we use the l_hNewProcessObj which is created. And this is the raw pointer
    CTestImpl* CMyImpl::createProcessObject(string f_hStrSFID, string f_nCallID,
                                           bool f_boReceiveCall)
    {
    CTestImpl * l_hNewProcessObj = NULL;
        ReturnCode l_eReturnCode = RETURNCODE_SUCCESS;

        l_hNewProcessObj = new (std::nothrow) CTestImpl(f_nCallID, f_hStrSFID, f_boReceiveCall,
                                                        m_nVSFSocketHandle, this);
        return l_hNewProcessObj;
    }

    And in the below handleTestEvents function we are using this createProcessObject function

    ReturnCode CMyImpl::handleTestEvents(CXMLObject* f_hMsgObj)
    {
            string l_hStrConfCallID = f_hMsgObj->getConfCallID();
            string l_hStrCallID = f_hMsgObj->getCallID();

            string l_StrMessageName = f_hMsgObj->getMessgeName();
            ReturnCode l_eReturnCode = RETURNCODE_SUCCESS;
            if(strcmp(l_hStrConfCallID.c_str(), "0") != 0
                    && strcmp(l_hStrConfCallID.c_str(), "") != 0)
            {
                l_hStrCallID = l_hStrConfCallID;
            }

    CTestImpl *l_hProcessObj = NULL;

            if (0 == l_StrMessageName.compare(REQ_XML_MESSAGE_CALL)
                || 0 == l_StrMessageName.compare(REQ_XML_MESSAGE_FIRST_CALL))
            {
                if (0 == strcmp(l_StrMessageName.c_str(),REQ_XML_MESSAGE_FIRST_CALL))
                {
                    m_hEventListener->setDeviceStatus(true);   
                    if (NULL == getCallObjectOfThisID(l_hStrCallID))
    //create Process object....
                    {
                        l_hProcessObj = createProcessObject(m_strSoftPhoneName,l_hStrCallID,true,false);
                    }
                    if (NULL != m_hlstCallList)
                    {
                        m_hlstCallList->push_back((l_hProcessObj));
                    }
                    m_hEventListener->handleAllEvents(MSG_SP_CALL,
                                                       static_cast<ICall*>(l_hProcessObj));
         }
    }

    In the above function, the createProcessObject is allocating the pointer
    And this is getting pushed into the list
    And then this is calling the below handleAllEvents function.

    void CTestManager::handleAllEvents(Events f_MyEvent,
                                       EMRCall::ICall* f_hProcessObject)
    {
    Message* l_hMessage = new Message();
            l_hMessage->m_eEvents = f_MyEvent;
            l_hMessage->m_hProcessObj = f_hProcessObject;

     if(nullptr != f_hProcessObject)
    {
                l_hMessage->m_hStrSoftphone = f_hProcessObject->getDeviceID();
            }
            m_hMessageQueueObj->postMsg(l_hMessage);
    }

    Here in CTestManager also f_hProcessObject is a raw pointer and it is getting assigned here.
    This raw pointer is also used in the list in the CTestImpl
    Now this message is posted to the message queue using the statement:
    m_hMessageQueueObj->postMsg(l_hMessage);

    Here we have a kind of situation where we will have a Processobject kind of shared data which is passed from the CMyImpl to the CTestManager as a raw pointer.
    So you have the same memory which is pointed to by the processobject data being used in two separate threads
    This is the kind of contention between the shared memory which should be handled properly between two threads
    How we are going to handle this?

    Could some one please help me how to handle this kind of situation.

    I have few options in mind like as shown below:

    1. You can’t control the same memory from two different threads until you have critical section locks before changing the state of process object and protected before reading from it

    2. Other option is you create a copy of the object. Only pass the copy to the other side
    Because we are not going to write anything to the object We are only reading the information 

    3. The other option is go with the thread less architecture wherein you don’t have threads
    So that at a time one can access it

    Please provide your valuable inputs and suggestions to proceed further.

    Thanks in advance.

                                            

    Monday, August 10, 2020 5:14 PM

Answers

  • Hi,

    Thank you for posting here.

    >>How to handle the situation where shared data (shared memory) using raw pointers being used in two separate threads in C++? 

    If all shared data (shared memory) is read-only, there is no issue, because the data read by one thread is not affected by whether another thread reads the same data.

    A race condition occurs when multiple threads are reading and writing data, and the final result depends on the order in which multiple processes are executed.

    I suggest you could try to use a mutex Class to protect a shared resource from simultaneous access by multiple threads or processes. Each thread must wait for ownership of the mutex before it can execute the code that accesses the shared resource. 

    I suggest you could try to construct a mutex object. by std::mutex, and then call the member function lock() to lock the mutex, call the member function unlock() to unlock it.

    You could also try to use lock_guard Class.

    Best Regards,

    Jeanine Zhang


    "Visual c++" forum will be migrating to a new home on Microsoft Q&A !
    We invite you to post new questions in the "Developing Universal Windows apps" forum’s new home on Microsoft Q&A !
    For more information, please refer to the sticky post.

    Tuesday, August 11, 2020 7:18 AM

All replies

  • Reading or writing?

    Race conditions technically only occur if at least one thread is trying to modify a block of memory. This means that if, besides the original writing to the block of memory to initialise it, your only access is to read it then you don't have to bother protecting it at all.


    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.

    Tuesday, August 11, 2020 1:32 AM
  • Thank you @Darran Rowe

    In the first thread we are pushing the object l_hProcessObj into the list
    Then we are passing this l_hProcessObj shared data to the second thread as a raw pointer

    In the second thread we are setting this f_hProcessObject to the message member
    Here we have the same memory which is pointed to by the processobject being used in two separate threads.

    And there is a chance that this object is used in other threads in the project with write operation.

    Tuesday, August 11, 2020 4:08 AM
  • Hi,

    Thank you for posting here.

    >>How to handle the situation where shared data (shared memory) using raw pointers being used in two separate threads in C++? 

    If all shared data (shared memory) is read-only, there is no issue, because the data read by one thread is not affected by whether another thread reads the same data.

    A race condition occurs when multiple threads are reading and writing data, and the final result depends on the order in which multiple processes are executed.

    I suggest you could try to use a mutex Class to protect a shared resource from simultaneous access by multiple threads or processes. Each thread must wait for ownership of the mutex before it can execute the code that accesses the shared resource. 

    I suggest you could try to construct a mutex object. by std::mutex, and then call the member function lock() to lock the mutex, call the member function unlock() to unlock it.

    You could also try to use lock_guard Class.

    Best Regards,

    Jeanine Zhang


    "Visual c++" forum will be migrating to a new home on Microsoft Q&A !
    We invite you to post new questions in the "Developing Universal Windows apps" forum’s new home on Microsoft Q&A !
    For more information, please refer to the sticky post.

    Tuesday, August 11, 2020 7:18 AM
  • Additionally, you need to consider how the lifetime of the object being used by different threads is managed. What if one thread destroys the object while another thread is trying to use it?
    Tuesday, August 11, 2020 9:07 AM
  • Thank you for your inputs:

    Can i try the below option:

    Once we create the ProcessObject (shared memory) using createProcessObject function in the first thread, and then send the 'l_hProcessObj' to the second thread using the below line:

    m_hEventListener->handleAllEvents(MSG_SP_CALL,static_cast<ICall*>(l_hProcessObj));

    Can we transfer the complete ownership of the ProcessObject to the second thread in CTestManager class. In this case there is no need to maintain the ProcessObject pointer in the first thread in CTestImpl class. Here we can create the object but once you pass the pointer to the CTestManager (2nd thread) we can just relinquish the control and don’t use it.

    Tuesday, August 11, 2020 12:30 PM
  • How and when does the object get destroyed?

    Or does it just turn into a memory leak?

    Tuesday, August 11, 2020 12:46 PM
  • Hi @RLWA32

    In the second thread that is in handleAllEvents function, we are posting the messages in the user defined message queue. There we do polling for the new message that is posted and once it is processed we are deleting the object.

    Tuesday, August 11, 2020 2:02 PM
  • Earlier you wrote.

    "In the first thread we are pushing the object l_hProcessObj into the list
    Then we are passing this l_hProcessObj shared data to the second thread as a raw pointer

    In the second thread we are setting this f_hProcessObject to the message member
    Here we have the same memory which is pointed to by the processobject being used in two separate threads.

    And there is a chance that this object is used in other threads in the project with write operation. "

    So its not clear to me that you don't have a lifetime management issue if more than two threads use the object.  A common technique is to use a reference count to ensure that an object is not destroyed prematurely.


    • Edited by RLWA32 Tuesday, August 11, 2020 2:15 PM
    Tuesday, August 11, 2020 2:14 PM
  • Sorry for the confusion. There are two threads.

    In the first thread we are pushing the object l_hProcessObj into the list
    Then we are passing this l_hProcessObj shared data to the second thread as a raw pointer

    In the second thread we are setting this f_hProcessObject to the message member
    Here we have the same memory which is pointed to by the processobject being used in two separate threads.

    And then posting the message in the user defined message queue. There we do polling for the new message that is posted and once it is processed we are deleting the object.

    Tuesday, August 11, 2020 4:55 PM