[ace-users] Upgrade to ACE-5.3.1 causes access violation

11 views
Skip to first unread message

Douglas C. Schmidt

unread,
Mar 20, 2003, 7:51:24 PM3/20/03
to
Hi Ron,

Thanks for using the PRF.

>> ACE VERSION: 5.3.1
>>
>> HOST MACHINE and OPERATING SYSTEM: Windows 2000 SR-2
>> TARGET MACHINE and OPERATING SYSTEM, if different from HOST:
>> COMPILER NAME AND VERSION (AND PATCHLEVEL): MSVC++ 6.0 SP5
>>
>> AREA/CLASS/EXAMPLE AFFECTED:
>> Runtime...
>>
>> DOES THE PROBLEM AFFECT:
>> COMPILATION? No
>> LINKING? No
>> EXECUTION? Yes
>>
>> SYNOPSIS:
>> Self-destruction of an ACE_Task<ACE_MT_SYNCH> work great in ACE-5.2.4 but
>> now causes
>> an access violation in ACE-5.3.1 ACE_Message_Queue::enqueue_tail() line
>> 1285: this->Notify()
>>
>>
>> DESCRIPTION:
>> I have a manager that maintains a list of ACE_Task Objects. When one of
>> these objects needs
>> to be removed, I remove it from my list and post a STOP Message as follows:
>> ACE_Message_Block* pMBlk = 0;
>> ACE_NEW( pMBlk, ACE_Message_Block(0, ACE_Message_Block::MB_STOP) );
>> pTask->putq( pMBlk );
>>
>> The individual task objects have implemented the close() hook to delete
>> themselves once the
>> service thread has exited:
>> int MyTask::close( u_long flags )
>> {
>> // Service thread has exited, and this object is now invalid.
>> delete this;
>> return( 0 );
>> }
>>
>> When this code is rebuilt using ACE-5.3.1, a race is introduced between the
>> Task destruction
>> and the completion of ACE_Message_Queue:enqueue_tail() and it is obvious to
>> me the problem. My question is how can I implement the self-destruction of
>> a Task object gracefully. The two solutions I have found involve:
>> 1. Modify MyTask::close() to sleep for a time before 'delete this'. This
>> in fact works great but putting sleeps in feels like a hack.
>>
>> 2. Don't Implement the close() hook and have my manager 'wait' for the
>> Task's service thread to exit and then delete the task via the manager.
>> This is clean but I don't want my manager hung up on dieing tasks.
>>
>> Any suggestions would be greatly appreciated.

There's a discussion of how to shut down tasks gracefully in a sidebar
called "Destroying an ACE_Task" in Chapter 6 of C++NPv2
<www.cs.wustl.edu/~schmidt/ACE/book2/>.

Take care,

Doug


--
Dr. Douglas C. Schmidt, Professor TEL: (615) 343-8197
Electrical Engineering and Computer Science FAX: (615) 343-7440
Vanderbilt University WEB: www.cs.wustl.edu/~schmidt/
Nashville, TN 37203 NET: sch...@isis-server.isis.vanderbilt.edu

Ron Muck

unread,
Mar 21, 2003, 1:00:05 PM3/21/03
to
Thanks Doug for your tip...C++NPv2 has been sitting on my desk for a month
and things became much clearer once I read chapter six.

After reading up on "Destroying an ACE_Task" and reviewing the changes made
in the ACE_Message_Queue from ACE-5.2.4 and ACE-5.3.1 I have discovered what
may be something worth noting. The big difference and root of my access
violation is the addition of the Notification Strategy and how I signal my
task to be destroyed.

My task is dynamically created and I leverage the task's close() hook to
delete itself. To trigger the destruction of a task, the user of the task
enqueues a message block whose payload is size 0 and whose type is MB_STOP
(As described in C++NPv2 pg 167). My task's svc() thread will dequeue this
message block, determine it is a STOP Request, and exit the thread which in
turn triggers the close() hook used to delete itself.

From within the ACE_Message_Queue::enqueue_tail(...), the queue is GUARDED,
the message is queued, and the GUARD is release. With the advent of the
Notification Strategy, "this->Notify()" was added after the message is
queued, and more importantly, OUTSIDE of the influence of the Guard. My
task's svc() thread can dequeue the message, exit the thread, and delete
itself BEFORE the "this->Notify" is called and an Access Violation occurs.

I have worked around this issue by changing how I trigger the destruction of
a task: the user of the task simply deactivates the task's Message Queue
which will trigger the task's svc() thread to wake up and exit.

I have not studied the implementation of the ACE_Message_Queue's
Notification Strategy to determine if not guarding the "this->Notify()" is a
bug or an artifact of the framework. On the surface it appears that the
"this->Notify()" should be guarded.

Any insights/enlightenment are welcome,
--Ron

Douglas C. Schmidt

unread,
Mar 22, 2003, 1:05:51 PM3/22/03
to
Hi Ron,

>> Thanks Doug for your tip...C++NPv2 has been sitting on my desk for a month
>> and things became much clearer once I read chapter six.

Great!

>> After reading up on "Destroying an ACE_Task" and reviewing the
>> changes made in the ACE_Message_Queue from ACE-5.2.4 and ACE-5.3.1
>> I have discovered what may be something worth noting. The big
>> difference and root of my access violation is the addition of the
>> Notification Strategy and how I signal my task to be destroyed.

Ok.

>> My task is dynamically created and I leverage the task's close()
>> hook to delete itself.

Ok.

>> To trigger the destruction of a task, the user of the task enqueues
>> a message block whose payload is size 0 and whose type is MB_STOP
>> (As described in C++NPv2 pg 167).

Right.

>> My task's svc() thread will dequeue this message block, determine
>> it is a STOP Request, and exit the thread which in turn triggers
>> the close() hook used to delete itself.

Ok.

>> From within the ACE_Message_Queue::enqueue_tail(...), the queue is
>> GUARDED, the message is queued, and the GUARD is release. With the
>> advent of the Notification Strategy, "this->Notify()" was added
>> after the message is queued, and more importantly, OUTSIDE of the
>> influence of the Guard.

Right.

>> My task's svc() thread can dequeue the message, exit the thread,
>> and delete itself BEFORE the "this->Notify" is called and an Access
>> Violation occurs.

Yikes!

>> I have worked around this issue by changing how I trigger the
>> destruction of a task: the user of the task simply deactivates the
>> task's Message Queue which will trigger the task's svc() thread to
>> wake up and exit.

Right, that's another way to do it.

>> I have not studied the implementation of the ACE_Message_Queue's
>> Notification Strategy to determine if not guarding the
>> "this->Notify()" is a bug or an artifact of the framework. On the
>> surface it appears that the "this->Notify()" should be guarded.

I think this was done originally in an attempt to avoid deadlocks. I
agree with you, however, that the current semantics are broken for the
use-case you describe. I'm going to try moving the notify() calls
within the guard lock and see how this affects our test programs.

Thanks,

Reply all
Reply to author
Forward
0 new messages