Thread: deadlocking, not sure why...

  1. #1
    Registered User
    Join Date
    Aug 2008
    Posts
    188

    deadlocking, not sure why...

    here's the main code that populates a vector
    Code:
    // handle incoming data
    boost::lock_guard<boost::recursive_mutex> lock(__mutex);
    m_data.push_back(data); // vector of strings
    m_lb.AddString(item); // MFC CListBox
    m_lb.SetCurSel(m_data.size() - 1);
    OnListBoxChanged(); // event handler for CListBox
    the event handler
    Code:
    void OnListBoxChanged()
    {
      boost::lock_guard<boost::recursive_mutex> lock(__mutex);
      int index = m_lb.GetCurSel();
      m_txt.SetWindowText(m_data[index]); // a textbox
    }
    ok, so data is coming in really fast, and the program auto refreshes the dialog so that the textbox is updated. if at that time i click on another item in the listbox, it triggers the OnListBoxChanged event, and then it deadlocks. also, it doesn't happen easily...what i mean is i have to click the listbox as fast as humanly possible for it to deadlock.

    the thing i don't understand is....there's only 1 mutex!!! why's the program still deadlocking?

  2. #2
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Don't have experience with these things. But looking at http://www.boost.org/doc/libs/1_35_0...cks.lock_guard just to learn, I see that there is an exception for guard_lock, because it calls lock(). So, you know, check for exceptions to see what is going on. Or try another lock. Maybe unique_lock?

    I don't see an error to your logic, so try to see what happens...

  3. #3
    Registered User
    Join Date
    Aug 2008
    Posts
    188
    actually, it's exception safe, it doesn't throw any exceptions. if you use the helper function boost::try_lock(...) that will throw an exception.

    i thought maybe it was something weird with boost (highly unlikely of course), so i tried it with InitializeCriticalSection, EnterCriticalSection, and LeaveCriticalSection and the same thing occurred.

    the read data thread that i've posted code is locked with the win32 thread of clicking the listbox triggering the event handler code.

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    You are aware, I suppose, that MFC is not supposed to be used in multiple threads?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    Aug 2008
    Posts
    188
    Quote Originally Posted by matsp View Post
    You are aware, I suppose, that MFC is not supposed to be used in multiple threads?

    --
    Mats
    thanks. that pointed to me in the right direction. i was using boost::thread to do my reading data thread, and it appears i should be using MFC specific thread creation functions.

  6. #6
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    To clarify - if you use any part of MFC in an additional thread, then that thread should be created using AfxBeginThread to ensure that the thread plays nicely within the framework. Also, you typically don't touch MFC UI objects from multiple thread - which is what I believe matsp was referring to.

    I would guess that your "deadlock" is probably due to calls to SendMessage() within your thread that are occurring "under the hood" of MFC. In the end, you'll want to keep UI stuff all within the main thread of the app and let any extra threads just do processing. You can post custom messages from your thread(s) if UI state needs to be "refreshed" or changed.

    gg

  7. #7
    Registered User valaris's Avatar
    Join Date
    Jun 2008
    Location
    RING 0
    Posts
    507
    Does the problem have anything to do with the fact that you aquire a lock in a function, then call another function that tries to get a lock when the previous lock was never released? Seems like that would cause deadlocking but I have zero experience with boost libraries.

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by valaris View Post
    Does the problem have anything to do with the fact that you aquire a lock in a function, then call another function that tries to get a lock when the previous lock was never released? Seems like that would cause deadlocking but I have zero experience with boost libraries.
    It is a "recursive mutex", so assuming that it does what is says on the label, it should allow the same thread to lock multiple times and only allow another thread in once all locks of the first thread have been released - of course care has to be taken that the lock is released exactly the same number of times that it was taken - otherwise problems with occur.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Quote Originally Posted by valaris View Post
    Does the problem have anything to do with the fact that you aquire a lock in a function, then call another function that tries to get a lock when the previous lock was never released? Seems like that would cause deadlocking but I have zero experience with boost libraries.
    It is automatically released with the destructor of the lock_guard object

  10. #10
    Registered User valaris's Avatar
    Join Date
    Jun 2008
    Location
    RING 0
    Posts
    507
    Well still the destructor wouldn't be called in the first function by the time hes waiting on the lock on the 2nd. But I didn't know that a recursive mutex worked as matsp described, so I guess that makes sense.

  11. #11
    Registered User
    Join Date
    Aug 2008
    Posts
    188
    Quote Originally Posted by valaris View Post
    Does the problem have anything to do with the fact that you aquire a lock in a function, then call another function that tries to get a lock when the previous lock was never released?
    theoretically speaking the code i've posted cannot deadlock by design. deadlock can only occur if there's a lock A waiting on lock B, and lock B is waiting on lock A. in my scenario, there is only 1 lock, and both segments of code do not wait on anything, thus my scenario *should* be impossible to deadlock.

    i haven't gotten around to fixing it yet, but it's likely that i used boost::thread instead of AfxBeginThread like already mentioned.

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by bling View Post
    theoretically speaking the code i've posted cannot deadlock by design. deadlock can only occur if there's a lock A waiting on lock B, and lock B is waiting on lock A. in my scenario, there is only 1 lock, and both segments of code do not wait on anything, thus my scenario *should* be impossible to deadlock.

    i haven't gotten around to fixing it yet, but it's likely that i used boost::thread instead of AfxBeginThread like already mentioned.
    Yes, but MFC internal functions definitely have their own locks, so if for some reason you call the function that requires YOUR lock from a function that holds the internal lock and at the same time your other thread wants to get hold of the MFC lock, it will go wrong.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #13
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    You don't need two locks. For example: your thread does a SendMessage() with __mutex acquired. This in turn causes other messages to be dispatched in the main thread - which could then try to acquire __mutex in the main thread. Now the main thread is blocked on __mutex and your thread is blocked waiting on SendMessage() to return. But it can't return until __mutex is released. But __mutex won't be released until SendMessage() returns. Dead.

    Run the code in the debugger. Reproduce the deadlock. Examine the call stack of the main thread and your thread and see exactly where/what they are blocking on.

    gg

  14. #14
    Registered User
    Join Date
    Aug 2008
    Posts
    188
    Quote Originally Posted by Codeplug View Post
    You don't need two locks. For example: your thread does a SendMessage() with __mutex acquired. This in turn causes other messages to be dispatched in the main thread - which could then try to acquire __mutex in the main thread. Now the main thread is blocked on __mutex and your thread is blocked waiting on SendMessage() to return. But it can't return until __mutex is released. But __mutex won't be released until SendMessage() returns. Dead.
    damn that made my head spin soooo many times...lol...

    anyways, to answer your question, the 2 threads blocking are:
    1) the RunModalLoop() function from the main dialog, which ends up calling OnListBoxChanged()
    2) the boost::thread reading and calling OnListBoxChanged after changing the vector

  15. #15
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    So they are both in OnListBoxChanged() - but where exactly?
    lock constructor, GetCurSel, SetWindowText, or lock destructor?

    If you comment out GetCurSel and SetWindowText does the deadlock still occur (in the same place).

    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 05-08-2008, 09:50 AM