Click to See Complete Forum and Search --> : Critical_section


indiana_pippis
September 13th, 2007, 03:59 AM
Hi, I have a problem using the CRITICAL_SECTION: I have a thread that access to a list locking a criticalsection, the data are inserted in the list intercepting a message coming from a popup menu, the problem is that when the function try to add an element in the list and the critical section is lockedby the thread both the thread and the function called intercepting the popup menu message are stopped. Probably the problem is that the message queue of the application is locked (waiting for the critical section) and all the thread of the application are stopped until the queue is locked.

How I can solve the problem?

Igor Vartanov
September 13th, 2007, 04:07 AM
The CRITICAL in this entity name denotes that it is inteneded for protection of only critical fragments of your code. In other words you enter the CS only when you have to provide the data stability, then you copy data locally (or make any other action) and leave the section a.s.a.p., letting other your code fragments wait not too long. After leaving the CS your code deals only with local data copy.

indiana_pippis
September 13th, 2007, 04:27 AM
I have a list...
I need to monitor the list using a thread (this operation is very short)... but this operation need to lock the list to avoid that the list change during this operation.
The insertion of a new element is a very short operation and need to lock the list...

the problem is that the function that add the element in the list is called when a message is intercepted and when this function wait for the critical section all the thread of the application are stopped...

I need to know how I can release the message queue

Arjay
September 13th, 2007, 04:36 AM
Are you sure you are always releasing the lock?

indiana_pippis
September 13th, 2007, 04:43 AM
yes, the functions are very simple...



AddFunction()
{
EnterCriticalSection();
m_List.AddTail(...);
LeaveCriticalSection();
}

MonitoringThread()
{
...
while(...)
{
EnterCriticalSection();
pos=m_List.GetHeadPosition();
while(pos)
{
el=m_List.GetNext();
...
}
LeaveCriticalSection();
Sleep(100);
}

Igor Vartanov
September 13th, 2007, 05:18 AM
Per your description, the list element insertion is a short operation. Once your code suffers from blocking, I can suppose you do not leave the CS. It may happen on lots of reasons.

See sample.

indiana_pippis
September 13th, 2007, 05:20 AM
probably I undestened the problem...
the monitoring thread update the text in a CListCtrl so send same messages... but the message queue are locked by the critical section...

How I can intercept the message of the popum menu call the EnterCriticalSection() without lock the message queue?

Igor Vartanov
September 13th, 2007, 05:27 AM
There must not be any message sending code inside Enter-Leave CS braces. As I said, you obtain data securely and leave CS. After that you do with locally copied data.

How I can intercept the message of the popum menu call the EnterCriticalSection() without lock the message queue?Define two different messages instead.

indiana_pippis
September 13th, 2007, 05:34 AM
the message are not sent by enter and leave critica section, but:
I intercept a message and call EnterCriticalSection()...
If the function is locked by EnterCriticalSection() the message queue are locked...
the thread that monitor the list update a CListCtrl so it need to send same messages... but the message queue is locked... so the thread is locked and can not leave the critical section...
If the critical section is not released the message queue can not be released...

So I need to release the message queue befor call EnterCriticalSection()...

Any idea?

Igor Vartanov
September 13th, 2007, 05:49 AM
I hardly can understand your wording.

The function cannot be locked by EnterCriticalSection - it's a critical section object gets locked. Once your message handling results in a message sending, the same handler (or another one that uses the same critical section object) is called - but the CS remains not left yet, and the second critical section locking attempt happens. Since this locking is done in the context of the same (GUI) thread, that gives you a deadlock state.

That's why I said you about not letting the message sending between Enter and Leave.
A message sending may be with a high probability a result of the call of a member function of control object.

indiana_pippis
September 13th, 2007, 06:09 AM
the Add() function is locked by EnterCriticalSection() because the thread already call this function.
The Add function is called intercepting a message.
until the Add function is waiting for the critical section the message queue is locked.
The thread update a CListCtrl, so the thread need to send messages. each time it sends a message wait until the message is processed.
But if the message queue is locked the message can not be processed.


So I need to release the message queue befor call EnterCriticalSection()...

Anyone know how I can do it?

Igor Vartanov
September 13th, 2007, 06:25 AM
Do you really think that repeating the same question in the same terminology can help anything?

To "release the message queue" you just do not block it with re-entering Add function. How can you do this depends on you. Definitely you have to re-arrange your code in aspect of critical section entering-leaving.

indiana_pippis
September 13th, 2007, 06:54 AM
I momentaniusly use the following code:



while(!TryToEnterCriticalSection(&m_cs))
{
MSG msg;
while (PeekMessage(&msg, 0, 0, 0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Sleep(10);
}


It run because the message queue is not locked, but I don't want to use the Sleep() function...

Edders
September 13th, 2007, 08:23 AM
My apologies if I'm warning for something you already know - but the code below (which i copied from from one of your previous posts) is not exception safe. I do not think this is the issue you are having right now - but it is worth mentioning.

AddFunction()
{
EnterCriticalSection();
m_List.AddTail(...);
LeaveCriticalSection();
}
If the function m_List.AddTail throws an exception then the processor will leave the function there and not execute the LeaveCriticalSection() function - and your critical section will from then on always be blocked.

The simplest fix is by creating a small critical section class that locks the section in the ctor and unlocks it in the dtor. By creating a local object of the class you lock the section and when the object goes out of scope the section will be automatically unlocked. Regardless of the reason for going out of scope - wether it be normal execution or exception.

Arjay
September 13th, 2007, 12:13 PM
Igor has been telling you the problem exactly, but you aren't quite seeing it. Don't worry about it - let's take another stab at it.

Based on the code snippet you are providing, I am assuming that the Add function is a message handler and gets called when a message is sent to the main thread by the secondary thread. If this is correct, the secondary thread sends a message to the main thread hopefully where I've edited your code (below in red)


AddFunction()
{
EnterCriticalSection();
m_List.AddTail(...);
LeaveCriticalSection();
}

MonitoringThread()
{
...
while(...)
{
EnterCriticalSection();
pos=m_List.GetHeadPosition();
while(pos)
{
el=m_List.GetNext();
SendMessage( hWndMain, WM_USER_ADD, 0, 0 );
}
LeaveCriticalSection();
Sleep(100);
}
}


If your code is similar to what I have proposed above, this is the problem (and what Igor was saying). Here's why it doesn't work. What will happen is T2 (monitoring thread) will lock the cs, iterate through the list, and call the SendMessage. This will cause the T1 (main thread) to respond to the WM_USER_ADD message which calls the AddFunction handler. AddFunction in turn attempts to obtain the lock on the cs - WHICH IT CAN'T obtain because T2 has not yet released the lock. Result == deadlock.

Now, depending on what you are trying to do, you may be able to just move the SendMessage call to after the LeaveCriticalSection call.


AddFunction()
{
EnterCriticalSection();
m_List.AddTail(...);
LeaveCriticalSection();
}

MonitoringThread()
{
...
while(...)
{
EnterCriticalSection();
pos=m_List.GetHeadPosition();
while(pos)
{
el=m_List.GetNext();
}
LeaveCriticalSection();
SendMessage( hWndMain, WM_USER_ADD, 0, 0 );
Sleep(100);
}
}


I say depending because if the main thread just needs to know that the list has been updated, above will work. If you need to signal the main thread on a per list item basis, then you need to figure out a different strategy.

If this is the case, please let us know and we can help you develop a new strategy.

ovidiucucu
September 13th, 2007, 12:16 PM
[ Redirected thread ]

Arjay
September 13th, 2007, 12:25 PM
I momentaniusly use the following code:



while(!TryToEnterCriticalSection(&m_cs))
{
MSG msg;
while (PeekMessage(&msg, 0, 0, 0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Sleep(10);
}


It run because the message queue is not locked, but I don't want to use the Sleep() function...This code is only masking the underlying issue - it isn't solving the problem. See my previous post for specifics.

Edders
September 13th, 2007, 05:53 PM
If the code is indeed similar to what Arjay posted previously, then you may be able to fix it by using PostMessage() instead if SendMessage(). PostMessage will just add the message to the queue without waiting for it to be processed.

Arjay
September 14th, 2007, 12:16 AM
If the code is indeed similar to what Arjay posted previously, then you may be able to fix it by using PostMessage() instead if SendMessage(). PostMessage will just add the message to the queue without waiting for it to be processed.SendMessage was a typo, I meant to say PostMessage. However, in either case if the message is sent while iterating the list, the deadlock will remain.

Igor Vartanov
September 14th, 2007, 05:25 AM
probably I undestened the problem...
the monitoring thread update the text in a CListCtrl so send same messages... but the message queue are locked by the critical section...

How I can intercept the message of the popum menu call the EnterCriticalSection() without lock the message queue?I re-read this thread carefully. It seems I already told you all I have to tell. Well, let's try another way.

MonitoringThread()
{
...
while(...)
{
EnterCriticalSection(); // here you block the GUI thread
pos=m_List.GetHeadPosition();
while(pos)
{
el=m_List.GetNext();
...
// here you never do something with messages and controls !!!!
// remember I told you about copying the data from protected list
// to local storage - this means you create another list locally
// and fill it with the data you need to process later
// since copying is typically a fast operation, you reach LeaveCriticalSection
// below rather fast
}
LeaveCriticalSection();

// here you already unblocked the GUI thread
// and at last, you are able to run through your local list
// and do with messages and controls

Sleep(100);
}