0

I pass params structure, which contains shared_ptr to std::deque, as input argument for function, which would work in a new thread. This deque created on the external object as a public field. And when I save shared_ptr to the params structure, number of refs at shared_ptr is incremented, and all seems to be ok.

As for thread, it is created with help of calling _beginthread() function. Inside the thread, I push some values to deque, pointed by shared_ptr. These values are popped at the external object correctly, so everything seems to be ok again.

When thread finishes it's work, params structure deleted from heap and ref counter decremented (all is fine again). But when destructor of external object, where this shared_ptr was created, is called then refs counter is decremented and equals 0, so destructor of pointed object is actually called, and debug assertation failure appears. Failed expression is _pFirstBlock == pHead (double delete?). But I checked with help of Data breakpoint at VS2012, that address of shared_ptr._Rep._Uses is only accessed at moments I described above.

One more note: if nothing pushed into this deque, then all destructors run successfully. What I'm doing wrong?

typedef std::deque<MsgBuf_ptr> MsgQueue;
typedef std::tr1::shared_ptr<MsgQueue> MsgQueue_ptr;
typedef const MsgQueue_ptr& MsgQueue_ptr_p;

shared_ptr creation:

...
MsgQueue_ptr qMsgQueue;
...
qMsgQueue.reset(new MsgQueue)
...
bool bStartOK = start(qMsgQueue, ghMutex);  

thread param structure:

struct ThreadServerParam {  
    HANDLE ghStopEvent;
    MsgQueue_ptr qMsgQueue; 
    HANDLE ghMutex;
};

thread creation:

void start(MsgQueue_ptr_p qMsgQueue, HANDLE ghMutex) {
    param = new ThreadServerParam;
    param->qMsgQueue = qMsgQueue;   
    param->ghStopEvent = ghStopEvent;
    param->ghMutex = ghMutex;

    hThread = (HANDLE)_beginthread( &ThreadFunction, THREAD_STACK_SIZE, param );
    if(hThread == INVALID_HANDLE_VALUE || hThread == NULL) {...}
}

thread function:

void ThreadFunction(void* ptr) {
    ThreadServerParam *param = (ThreadServerParam*) ptr;    
    while(dwWaitResult != WAIT_OBJECT_0) {          
        findNewMessage(internalQueue);
        if(!msgQueue->empty()) {                
        DWORD dwWaitResult = WaitForSingleObject(param->ghMutex, INFINITE);
        switch (dwWaitResult) {
                case WAIT_OBJECT_0: 
                    while (!msgQueue->empty()) {
                        MsgBuf_ptr msg_buf = internalQueue->front();
                        param->qMsgQueue->push_back(msg_buf);                                   
                        internalQueue->pop_front();
                    }
             ...
            }
          }
          Sleep(GAP);
      dwWaitResult = WaitForSingleObject(param->ghStopEvent, 0);
     }
     delete param;
 }
3ka5_cat
  • 121
  • 1
  • 12
  • Passing a pointer as a reference is kind of pointless (pun maybe intended) unless you want to modify the pointer, and that goes for the smart pointers as well. It's just one more level of indirection for the compiler to handle. I'm talking, of course, about the `qMsgQueue` parameter in the `start` function. – Some programmer dude May 16 '14 at 14:18
  • 1
    @JoachimPileborg passing `std::shared_ptr` by reference prevents the slight overhead of incrementing the internal reference counter of the `std::shared_ptr`. While this probably won't have a huge impact on performance, in some tight loops or critical parts of code it may make a difference. – YoungJohn May 16 '14 at 14:30
  • Anyway, using or not 'pass by reference' doesn't have effect to my trouble :) – 3ka5_cat May 16 '14 at 14:37
  • 1
    I don't see a refcount problem in this code, unless the `const` in `MsgQueue_ptr_p` prevents its copy from incrementing the refcount. Does going fuller C++11, and using `std::shared_ptr` instead of the tr1 variant and `std::thread` instead of `_beginthread` help? – Michael Urman May 16 '14 at 15:06
  • do you enforce destruction order of your created thread and main thread? if not then both of them could be trying to delete the object pointed by shared_ptr because both of them they have seen the ref decrement to 0 and are responsible for the deletion. – swang May 18 '14 at 20:44
  • @MichaelUrman in case of `std::shared_ptr` and oldschool `_beginthread` problem still persist, but in case of `std::thread` and `std::shared_ptr` no assertation throws. Thx – 3ka5_cat May 19 '14 at 10:50

0 Answers0