Access Violation after Update 2 installed

Hello. I have started receiving an access violation after installing Update 2. I have installed update 4 and the problem still persists. The access violation occurs whenever the application's main form loses focus after loading and then deleting a child form. It appears that when the main form loses focus, it attempts to access the last active child form, which is not valid because it deleted when it wa snot longer being used. The accessing of the child form is not taking place in my code. Does anyone kno
w of a fix or a workaround for this issue?
0
Rick
12/16/2009 1:41:34 AM
embarcadero.cppbuilder.install 385 articles. 0 followers. Follow

14 Replies
603 Views

Similar Articles

[PageSpeed] 35

"Rick Dickerson" wrote in message news:194341@forums.codegear.com...

> Hello. I have started receiving an access violation after installing 
> Update 2.

Update 2 of what product?  Please provide the name and version of the IDE 
you are using.

> The access violation occurs whenever the application's main form loses 
> focus

The problem is most likely with your code.  If you can, create a small 
example that demonstrates this behavior and post the code.  If you are 
unable to make a small enough example ( < 300 lines) then zip up your source 
and post to the attachments forum.  Be sure to reference this post so people 
will be able to know what post it belongs to.

Clayton
0
Clayton
12/16/2009 4:03:55 PM
> {quote:title=Clayton Arends wrote:}{quote}
> "Rick Dickerson" wrote in message news:194341@forums.codegear.com...
> 
> > Hello. I have started receiving an access violation after installing 
> > Update 2.
> 
> Update 2 of what product?  Please provide the name and version of the IDE 
> you are using.
> 
> > The access violation occurs whenever the application's main form loses 
> > focus
> 
> The problem is most likely with your code.  If you can, create a small 
> example that demonstrates this behavior and post the code.  If you are 
> unable to make a small enough example ( < 300 lines) then zip up your source 
> and post to the attachments forum.  Be sure to reference this post so people 
> will be able to know what post it belongs to.
> 
> Clayton

Sorry I wasn't clear about that. The update was for C++Builder® 2010 Version 14.0.3593.25826. I will work on a small example that will demonstrate the problem. Do you know if Update 2 for Builder 2010 contained any updates to the VCL? If so, what areas were affected? I am not disputing that my code could be at fault. However, the code worked before the update so some change in the update is either directly responsible for the error or is exposing a problem in my code. I am trying to figure out what the is
sue is so it can be fixed.

Edited by: Rick Dickerson on Dec 16, 2009 5:21 PM
0
Rick
12/17/2009 1:23:29 AM
I have built a test application and posted it to the Attachments forum (https://forums.embarcadero.com/thread.jspa?threadID=30204). The issue is being caused by disabling a timer in a modal form from another thread. Here is some background on the application that I am seeing this issue in. The application is quite large and allows remote connections. When data is being transferred and processed a progress dialog box is shown. If no data is received within a specified time, the dialog box will be automatic
ally canceled using a timer in the dialog box. Once data is received, the automatic cancellation timer needs to be turned off. It is this operation that is causing the access violation. After all data is received and processed, the dialog box is programatically dismissed by setting the ModalResult variable. This application uses standard Windows threads instead of Builder's TThread object and switching to TThread objects is not viable at the time. Because TThreads are not used, there is no Synchronize met
hod for the many threads this application starts. We have seen issue with modifying GUI components from a separate thread, so we have developed a scheme to use timers to update the GUI from other threads. Basically a non-GUI thread will call a method on a form when the GUI needs to be updated. The form's method will set flags and variables according to the request and start a timer with a very short interval (usually 1 mS) that will use the flags and variables to update the GUI as needed. In some places, 
we use a timer that is always running to update the GUI, but the external update request is essentially the same. We use this scheme in a lot of places and have had no problems before or after update 2 to Builder 2010. However, we only disable a timer in a modal form from a separate thread in a single form and that blew up after update 2 to Builder 2010. I have tried using our typical timer scheme so the external thread would call a method in the modal form to start a timer that will kill the cancellation
 timer, but that still results in the access violation. It seems like the issue may be related to the form being modal. Does anyone know of any changes in update 2 to Builder 2010 that would cause this issue. I would also be interested to know if anyone has a better solution to updating a GUI from a separate thread. As I said before, switching to TThreads is not a viable solution right now.

The sample project I submitted has one issue that I do not completely understand, but it does not show up in my real application. When I dismiss the dialog box programatically, it will sometimes take a long time to disappear. I suspect this is because of the access violation. If that happens and you take focus from the application, you can still see the access violation.
0
Rick
12/21/2009 11:10:06 PM
I have just returned from an extended holiday and saw your post.  I expect 
to be able to free up some time soon to look at your sample program.  I 
wanted to write this post so you know *someone* is taking a further look 
into your problem.

Clayton
0
Clayton
1/4/2010 5:26:33 PM
> {quote:title=Clayton Arends wrote:}{quote}
> I have just returned from an extended holiday and saw your post.  I expect 
> to be able to free up some time soon to look at your sample program.  I 
> wanted to write this post so you know *someone* is taking a further look 
> into your problem.
> 
> Clayton

Thanks for updating the thread.
0
Rick
1/4/2010 10:57:30 PM
"Rick Dickerson" wrote in message news:196380@forums.codegear.com...

> I have built a test application and posted it to the Attachments forum

I didn't encounter an AV but that may have just been luck (or unluck).  The 
general problem with the design (as you have stated) is that you are 
accessing the VCL objects' properties in a non thread-safe manner.  It is 
possible for the main application thread and your DismissalThread to collide 
via access to the ModalResult, and AutoCancel->Enabled properties.  Access 
to these properties needs to be synchronized with the main application 
thread (again, as you have stated).

> This application uses standard Windows threads instead of Builder's 
> TThread object and switching to TThread objects is not viable at the time.

It would be far easier to use TThread::Synchronize to solve this problem. 
However, if you can't do that then an alternative would be to create a 
synchronize event of your own.  I will outline this below.  First, I would 
like to mention other problems that I found with your code:

1. DismissalThread::dismissThread() has an invalid definition to be used 
with CreateThread.  It needs to look like the following instead:

  static DWORD WINAPI dismissThread (void* clsPtr);

After making this change you should also notice that you'll be able to 
remove the typecast performed on line 26 of DismissalThread.cpp.

2. If the user clicks the TTTestForm::btCancel button then the form is 
destroyed prior to the thread code reaching line 44 of DismissalThread.cpp. 
This results in that line accessing an invalid pointer.  To prove this point 
add a destructor to TTTestForm with the following code in it:

  AutoCancelTimer = NULL;

Run the app, display the test form, click the cancel button and you will 
receive an AV.

Similarly, if the user clicks the button after line 44 runs but before line 
48 runs the same case as above happens (though there's no way to force the 
AV like the first case ... luck is required).

> The sample project I submitted has one issue that I do not completely 
> understand, but it does not show up in my real application. When I dismiss 
> the dialog box programatically, it will sometimes take a long time to 
> disappear.

This happens because setting ModalResult does not immediately cause any 
message handling to take place.  It only updates the value of 
TForm::FModalResult.  If you move your mouse over the form you will notice 
the form gets closed.  To cause the close to happen immediately add the 
following call after setting the modal result:

  parentObj->dlgToDismiss->Refresh();

Okay, as promised here is a custom technique for creating a synchronize.  To 
do this, set aside a custom windows message number (eg. WM_USER + 100). 
When your thread wants to synchronize access with the main thread then 
create a temporary object that will contain required data and an event to 
know when to continue execution.  Perform your custom Windows message to the 
application handle and pass your data along with the message.  Your main 
form should intercept application messages and handle your custom message 
accordingly.  Here is an example:

  // DismissalThread.h
  typedef void (__closure *TSyncMethod)();
  struct TSyncData
  {
    TSyncMethod Method;
    HANDLE Event;
  };

  static const WM_MY_SYNC = WM_USER + 100;

  class DismissalThread
  {
    //...
    private:
      void Synchronize(TSyncMethod Method);
    //...
  };

  // DismissalThread.cpp
  void DismissalThread::Synchronize(TSyncMethod Method)
  {
    TSyncData data;
    data.Method = Method;
    data.Event = ::CreateEvent(NULL, FALSE, FALSE, NULL);
    ::PostMessage(Application->Handle, WM_MY_SYNC, 0,
      reinterpret_cast <LPARAM> (&data));
    ::WaitForSingleObject(data.Event, INFINITE);
    ::CloseHandle(data.Event);
  }

  // In MAIN drop a TApplicationEvents object on your form.  Add
  // an event handler for the OnMessage event.  Put the following
  // in the event handler.
  void __fastcall TMainForm::ApplicationEvents1Message(
    tagMSG &Msg, bool &Handled)
  {
    if (Msg.message == WM_MY_SYNC)
    {
      try
      {
        reinterpret_cast <TSyncData*> (Msg.lParam)->Method();
      }
      catch (...)
      { // handle exception if desired
      }

      // Let DismissalThread::Synchronize know that the event has
      // been handled
      ::SetEvent(reinterpret_cast <TSyncData*> (Msg.lParam)->Event);
      Handled = true;
    }
  }

This technique is not battle-hardened but it should be an okay starting 
point.  It will also get around the problematic way you are doing things 
right now by allowing a thread to alter a timer's Enabled property which may 
not be a thread-safe operation.  Posting messages *is* a thread-safe 
operation.

HTH,
Clayton
0
Clayton
1/6/2010 7:34:31 PM
Thanks for the info. I will have to take some time to digest it all and make sure I understand you. Do you have any idea why our solution worked for years and then broke after we installed Update 2?
0
Rick
1/6/2010 8:15:13 PM
"Rick Dickerson" wrote in message news:200298@forums.codegear.com...

> Thanks for the info. I will have to take some time to digest it all and 
> make sure I understand you.

You're welcome.  I hope I didn't make it too confusing or at the very least 
didn't write bad code or ideas.

> Do you have any idea why our solution worked for years and then broke 
> after we installed Update 2?

It's hard to say.  CodeGear may have made some internal changes to 
TTimer::Enabled() (or something it calls).  However, since I wasn't able to 
replicate the AV I'm not 100% sure which line of code is the catalyst. 
There are some objects that can be accessed from many threads at once and do 
okay.  A general rule of thumb (that I live by) is any VCL object that can 
be dropped on the form should only be accessed via a single thread (usually 
the main application thread).

Clayton
0
Clayton
1/6/2010 10:21:28 PM
I have implemented your synchronization solution for one section of our project that is particularly intensive in terms of back end threads needing to update the front end GUI. The synchronization works well MOST of the time. However, if I force a lot of activity and GUI updates, the posted message is sometimes missed. I have put debug output strings before I post the message and when it is received. The message is being posted, but is never being passed into the app message processing function. If the me
ssage is never received, the front end has no chance to set the event that the Synchronize method is waiting for and the back end thread is hung indefinitely. The time it takes for the callback method to complete can vary dramatically, so we can't just use a timeout on the WaitForSingleObject call. Any idea why the message is not being posted?

Rick
0
Rick
1/9/2010 10:48:21 PM
> {quote:title=Rick Dickerson wrote:}{quote}
> I have implemented your synchronization solution for one section of our project that is particularly intensive in terms of back end threads needing to update the front end GUI. The synchronization works well MOST of the time. However, if I force a lot of activity and GUI updates, the posted message is sometimes missed. I have put debug output strings before I post the message and when it is received. The message is being posted, but is never being passed into the app message processing function. If the 
message is never received, the front end has no chance to set the event that the Synchronize method is waiting for and the back end thread is hung indefinitely. The time it takes for the callback method to complete can vary dramatically, so we can't just use a timeout on the WaitForSingleObject call. Any idea why the message is not being posted?
> 
> Rick

JUst a follow up on the previous question...I suspect this issue is related to a known issue with PostMessage (http://support.microsoft.com/kb/183116) because the window is being programmatically maniuplated (frame size/location changes( when the issue presents itself. I have changed the handle from Application->Handle to mainForm->Handle where mainForm is the window that should be receiving the message. The problem still exists after that change.

Rick
0
Rick
1/10/2010 2:17:59 PM
> JUst a follow up on the previous question...I suspect this issue is related to a known issue with PostMessage (http://support.microsoft.com/kb/183116) because the window is being programmatically maniuplated (frame size/location changes( when the issue presents itself. I have changed the handle from Application->Handle to mainForm->Handle where mainForm is the window that should be receiving the message. The problem still exists after that change.
> 
> Rick

I just realized that KB article I reference is for PostThreadMessage not PostMessage, so it may not apply. Just to clarify...I am using PostMessage.
0
Rick
1/10/2010 2:30:27 PM
"Rick Dickerson" wrote in message news:201399@forums.codegear.com...

> However, if I force a lot of activity and GUI updates, the posted message 
> is sometimes missed.

I'd have to see your code to determine if that was caused by the solution I 
presented or whether it's caused by an implementation detail.  I created a 
test program which maxed out thread usage and did a lot of GUI actions and 
didn't encounter any skipped messages.

Regardless, since you mentioned it, it *is* possible for some windows 
message handling routines to "eat" a message if it feels like it so I 
imagine a better solution could be attempted.  The VCL doesn't use a Windows 
message to handle its synchronization (I previously thought it did).  It 
does so using a global list that is iterated every time the application goes 
idle.  To see the implementation details open Classes.pas and look for 
CheckSynchronize and TThread.Synchronize.

You could do something similar by creating a global list, adding a handler 
for TApplicationEvents::OnIdle, and populating the list whenever you want to 
synchronize.  Here is an example:

  // .h file
  typedef void (__closure *TSyncMethod)();

  class TMyThread
  {
    private:
      HANDLE fHandle;

      static DWORD WINAPI Go(void* clsPtr);

    protected:
      virtual void Execute()=0;

      void Synchronize(TSyncMethod Method);

    public:
      TMyThread();
      virtual ~TMyThread();

      static void HandleSynchronizes();
  };


  // .cpp file
  struct TSyncData
  {
    TSyncMethod Method;
    HANDLE Event;
  };

  class TSyncMyThread
  {
    private:
      TList* fSyncs;
      CRITICAL_SECTION fMainLock;

    public:
      TSyncMyThread();
      ~TSyncMyThread();

      void Add(TSyncData& Data);
      void HandleSynchronizes();
  };

  static TSyncMyThread SyncMyThread;

  TSyncMyThread::TSyncMyThread()
  {
    ::InitializeCriticalSection(&fMainLock);
    fSyncs = new TList;
  }

  TSyncMyThread::~TSyncMyThread()
  {
    ::DeleteCriticalSection(&fMainLock);
    delete fSyncs;
  }

  void TSyncMyThread::Add(TSyncData& Data)
  {
    // Access to 'fSyncs' is mutually exclusive
    ::EnterCriticalSection(&fMainLock);
    fSyncs->Add((void*) &Data);
    ::LeaveCriticalSection(&fMainLock);
  }

  void TSyncMyThread::HandleSynchronizes()
  {
    // Access to 'fSyncs' is mutually exclusive
    ::EnterCriticalSection(&fMainLock);
    while (fSyncs->Count > 0)
    { // Loop until 'fSyncs' is empty

      // Remove the first entry from 'fSyncs'
      TSyncData* syncData = (TSyncData*) fSyncs->Items[0];
      fSyncs->Delete(0);

      // Allow other threads access to 'fSyncs'
      ::LeaveCriticalSection(&fMainLock);

      try
      {
        syncData->Method();
      }
      catch (...)
      { // Handle if desired
      }

      ::SetEvent(syncData->Event);

      // Enter the critical section again
      ::EnterCriticalSection(&fMainLock);
    }
    ::LeaveCriticalSection(&fMainLock);
  }


  TMyThread::TMyThread()
  {
    DWORD threadID;
    fHandle = ::CreateThread(NULL, 0, Go, (void *) this, 0, &threadID);
  }

  TMyThread::~TMyThread()
  {
    ::CloseHandle(fHandle);
  }

  DWORD WINAPI TMyThread::Go(void* clsPtr)
  {
    try
    {
      reinterpret_cast <TMyThread*> (clsPtr)->Execute();
    }
    catch (...)
    { // Handle if desired
    }

    delete reinterpret_cast <TMyThread*> (clsPtr);

    return 0;
  }

  void TMyThread::HandleSynchronizes()
  {
    SyncMyThread.HandleSynchronizes();
  }

  void TMyThread::Synchronize(TSyncMethod Method)
  {
    TSyncData data;
    data.Method = Method;
    data.Event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
    SyncMyThread.Add(data);
    ::WaitForSingleObject(data.Event, INFINITE);
    ::CloseHandle(data.Event);
  }


  // TApplicationEvents::OnIdle handler on main form
  void __fastcall TForm1::ApplicationEvents1Idle(
    TObject *Sender, bool &Done)
  {
    TMyThread::HandleSynchronizes();
  }


You'll notice that my class structure is starting to look very similar to 
TThread.  You should be able to take apart the above class and insert it 
into your application for your usage.

HTH,
Clayton
0
Clayton
1/10/2010 10:50:20 PM
> {quote:title=Clayton Arends wrote:}{quote}
> I'd have to see your code to determine if that was caused by the solution I 
> presented or whether it's caused by an implementation detail.  

Thanks for getting back to me on the weekend.

Here is code snippet with some generic names to make things easier to follow. As you can see, I modified your solution somewhat. Most notably, the main window's message handler does not signal the event. Instead, the callback function is used to signal the event to save time marshalling the parameters into a structure whose pointer is passed into the message as LParam. Also, we use a code assignment in the form constructor (Application->OnMessage = AppMessage) to set up the message handler instead of a VC
L handler dropped onto the form. These changes seem benign, but they are different than your original suggestion so I though I should point them out.

The code below operates as follows: The BackEnd class, which is created by MainForm, starts 2 threads: ThreadA and ThreadB. (In our application there is a ThreadC, but it uses the same paradigm and has been removed for clarification). When either of these threads needs to update the GUI, the corresponding synchronize call is made to either SynchronizeA or SynchronizeB. The Synchronize method verifies a message should be sent and then passes the callback function, callback event and message type into a gen
eric routine, postSychMessage, which sends the message to the main form. Only the callback function pointer is sent with the message. After sending the message, postSychMessage waits for the event to be signaled. The event are class memeber and are signaled by callback functions when they complete. The scheme allows one thread to interrupt the GUI processing of another thread, which is acceptable to our application because they operate on different parts of the GUI. The lost message occurs when the applic
ation, which has several additional threads running all the time, is doing a lot of intensive operations and SynchronizeA is being called almost continuously and SynchronizeB (and SynchronizeC for that matter) is not being called at all. It seems that the message is getting lost in all of the other 'stuff' going on. Aside from the WM_MOUSEMOVE event shown below, the application does not handle any other application messages. I have also verified that my message IDs are unique so I can't see anywhere our a
pplication is consuming the message. I have used breakpoints and debug strings to verify that the message is never getting to the AppMessage method. This issue does present itself outside the debugger.


In BackEnd.h
// I have tried using WM_MSGA and WM_MSGB as the same message since they do the same thing (force MainForm to call a callback function with no parameters. 
// I tried splitting the messages because they are used in different threads and I wanted to make sure that wasn't the issue.
#define WM_MSGA    (WM_USER + 100)
#define WM_MSGB    (WM_USER + 101)
typedef void (__closure *SyncMsgWriteCallback)();


class BackEnd 
{
    .
    .
    .
private:
    HANDLE eventA;
    HANDLE eventB;
    .
    .
    .
};

In Backend.cpp
BackEnd::BackEnd()
{
    Initialization
    .
    .
    .
    eventA = ::CreateEvent(NULL, FALSE, FALSE, NULL);
    eventB = ::CreateEvent(NULL, FALSE, FALSE, NULL);
    .
    .
    .
}

void SynchronizeA()
{    // This method is only called from backend thread A
    do some checks to make sure the message should be posted
    postSynchMessage(&fcnA, eventA, WM_MSGA);
}

void SynchronizeB()
{    // This method is only called from backend thread B
    do some checks to make sure the message should be posted
    postSychMessage(&fcnB, eventB, WM_MSGB);
}

void postSynchMessage (SyncMsgWriteCallback callbackFcn, HANDLE callbackEvent, UINT msgType)
{// I have tried posting the message and waiting in SynchronizeA and SynchronizeB separately rather then use
 // this shared function but I still saw the same error.

    ::ResetEvent(callbackEvent);

    ::PostMessage(mainForm->Handle, msgType, 0, reinterpret_cast <LPARAM> (&callbackFcn));

     // If I use a timeout here and use ::PeekMessage for messages that timeout the timedout messages are not in the queue
    ::WaitForSingleEvent (callbackEvent, INFINITE);
}


void funcA()
{
    .
    .
    .
    Do stuff including GUI manipulation
    .
    .
    .
    ::SetEvent (eventA);
}

void  funcB()
{
    .
    .
    .
    Do stuff including GUI manipulation
    .
    .
    .
    ::SetEvent (eventB);
}

In MainForm.h
class TTopForm : public TForm
{
    friend class BackEnd;
    .
    .
    .
protected:
    void __fastcall AppMessage (tagMSG &Msg, bool &Handled);
    .
    .
    .
}

In MainForm.cpp
__fastcall MainForm::MainForm (TComponent* Owner)
{
    Initialization
    .
    .
    .
    Application->OnMessage  = AppMessage;
    .
    .
    .
}

void __fastcall MainForm::AppMessage (tagMSG &Msg, bool &Handled)
{
    switch (Msg.message ){
    case WM_MOUSEMOVE :
        Handle mouse movement code

    Case WM_MSGA:
        try{
            SyncMsgWriteCallback *msgWriteCallback = reinterpret_cast <SyncMsgWriteCallback*> (Msg.lParam);

            (*msgWriteCallback) ();
        }
        catch (...){
            //! Exception handling code TBD
        }
        Handled = true;

        break;
    
    Case WM_MSGB :
        try{
            SyncMsgWriteCallback *msgWriteCallback = reinterpret_cast <SyncMsgWriteCallback*> (Msg.lParam);

            (*msgWriteCallback) ();
        }
        catch (...){
            //! Exception handling code TBD
        }
        Handled = true;

        break;
}
0
Rick
1/11/2010 2:13:55 AM
"Rick Dickerson" wrote in message news:201680@forums.codegear.com...

> Here is code snippet ...

Your changes look fine aside from typos in the code but I'm a forgiving 
person ;).  Putting your code into a test app I was able to create a 
condition where the synchronizing messages were eaten simply by moving the 
window via its caption bar.  I didn't do that in my previous tests but I 
believe the same would happen if I were to go back and try.  Given this 
result I believe it would be best if you modified your design to use the 
second option I presented in my previous post.

Using the second technique I modified your simplified design.  I'm 
presenting it here as one file (all part of my main form unit):

  typedef void (__closure *SyncMsgWriteCallback)();

  struct TSyncData
  {
    SyncMsgWriteCallback Callback;
    HANDLE Event;
  };

  class BackEnd
  {
    private:
      TList* fSyncs;
      CRITICAL_SECTION fMainLock;

      HANDLE eventA;
      HANDLE eventB;

      void AddSync(TSyncData& Data);
      void Synchronize(SyncMsgWriteCallback Callback, HANDLE Event);

    public:
      BackEnd();
      ~BackEnd();

      void SynchronizeA(SyncMsgWriteCallback Callback);
      void SynchronizeB(SyncMsgWriteCallback Callback);

      bool HandleSynchronizes();
  };

  BackEnd daBackEnd;

  BackEnd::BackEnd()
  {
    ::InitializeCriticalSection(&fMainLock);
    fSyncs = new TList;

    eventA = ::CreateEvent(NULL, FALSE, FALSE, NULL);
    eventB = ::CreateEvent(NULL, FALSE, FALSE, NULL);
  }

  BackEnd::~BackEnd()
  {
    ::DeleteCriticalSection(&fMainLock);
    delete fSyncs;

    ::CloseHandle(eventA);
    ::CloseHandle(eventB);
  }

  void BackEnd::AddSync(TSyncData& Data)
  {
    // Access to 'fSyncs' is mutually exclusive
    ::EnterCriticalSection(&fMainLock);
    fSyncs->Add((void*) &Data);
    ::LeaveCriticalSection(&fMainLock);
  }

  bool BackEnd::HandleSynchronizes()
  {
    // Access to 'fSyncs' is mutually exclusive
    ::EnterCriticalSection(&fMainLock);
    bool result = fSyncs->Count > 0;
    while (fSyncs->Count > 0)
    { // Loop until 'fSyncs' is empty

      // Remove the first entry from 'fSyncs'
      TSyncData* syncData = (TSyncData*) fSyncs->Items[0];
      fSyncs->Delete(0);

      // Allow other threads access to 'fSyncs'
      ::LeaveCriticalSection(&fMainLock);

      try
      {
        //
        syncData->Callback();
      }
      catch (...)
      { // Handle if desired
      }

      ::SetEvent(syncData->Event);

      // Enter the critical section again
      ::EnterCriticalSection(&fMainLock);
    }
    ::LeaveCriticalSection(&fMainLock);

    return result;
  }

  void BackEnd::Synchronize(SyncMsgWriteCallback Callback, HANDLE Event)
  {
    // Prepare the data
    TSyncData data;
    data.Callback = Callback;
    data.Event = Event;

    // Add the sync which will be handled when app goes idle
    AddSync(data);

    // Force message handling in case app is already idle
    ::PostMessage(Application->Handle, WM_NULL, 0, 0);

    // Wait for the callback to finish processing
    ::WaitForSingleObject(Event, INFINITE);
  }

  void BackEnd::SynchronizeA(SyncMsgWriteCallback Callback)
  { // This method is only called from backend thread A
    Synchronize(Callback, eventA);
  }

  void BackEnd::SynchronizeB(SyncMsgWriteCallback Callback)
  { // This method is only called from backend thread B
    Synchronize(Callback, eventB);
  }


  __fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
  {
    Application->OnIdle = AppIdle;
  }

  void __fastcall TForm1::AppIdle(System::TObject* Sender, bool &Done)
  {
    Done = !daBackEnd.HandleSynchronizes();
  }

  void __fastcall TForm1::Button1Click(TObject *Sender)
  {
    DWORD threadID;
    if (!ThreadA)
      ThreadA = ::CreateThread(NULL, 0, ThreadAProc, (void *) this, 0, 
&threadID);
    if (!ThreadB)
      ThreadB = ::CreateThread(NULL, 0, ThreadBProc, (void *) this, 0, 
&threadID);
  }

  void TForm1::SyncedA()
  {
    Form1->Left += random(3) - 1;
  }

  void TForm1::SyncedB()
  {
    Form1->Top += random(3) - 1;
  }

  DWORD WINAPI TForm1::ThreadAProc(void* cls)
  {
    while (true) // not real-world safe code
    {
      daBackEnd.SynchronizeA(Form1->SyncedA);
      Sleep(10);
    }
  }

  DWORD WINAPI TForm1::ThreadBProc(void* cls)
  {
    while (true) // not real-world safe code
    {
      daBackEnd.SynchronizeB(Form1->SyncedB);
      Sleep(10);
    }
  }

Here is the class declaration for TForm1:

  class TForm1 : public TForm
  {
    __published:
    TButton *Button1;
    void __fastcall Button1Click(TObject *Sender);
    private:
      HANDLE ThreadA;
      HANDLE ThreadB;

      static DWORD WINAPI ThreadAProc(void* cls);
      static DWORD WINAPI ThreadBProc(void* cls);

      void __fastcall AppIdle(TObject* Sender, bool &Done);
      void SyncedA();
      void SyncedB();

    public:
      __fastcall TForm1(TComponent* Owner);
  };

In your final version I think it would be best if BackEnd is modified to:
1. Have only one Synchronize method (perhaps just expose AddSync)
2. Each thread should maintain its own event handle

Of course, those decisions will be up to you and your team.

HTH,
Clayton
0
Clayton
1/11/2010 3:39:36 PM
Reply:

Similar Artilces:

Adware tried to install the instant I installed the FF 2.0.0.2 update
Name: Dylan McBride Email: vituloratgmaildotcom Product: Firefox Summary: Adware tried to install the instant I installed the FF 2.0.0.2 update Comments: Can someone explain to me why the very instant I installed the update for Firefox browser, to version 2.0.0.2 Webroot Spy Sweeper popped open showing it prevented an Adware from 180 Assistant/Zango? I am NOT impressed. I hope you are not using ADWARE in your browser. Browser Details: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2) Gecko/20070219 Firefox/2.0.0.2 ...

10.0.2 installed, still asks to install 10.0.2 update
I installed the 10.0.2 update about ten days ago and it is verified on the About page. However, I get numerous daily reminders to install the 10.0.2 update. So I checked "never check for updates" but that apparently isn't working either because I'm getting all of the reminders. So what's my only option: uninstall and then reinstall? I'm a bit leery of doing that: everything else seems to be functioning properly. However, when I previously installed the 10.0.1 update, numerous things were broken on my Win7 system and I had to revert to a restore poi...

To install or not to install?
What's the difference between installing qpsmtpd as in...=0A=0Aperl Makefil= e.PL=0Amake=0Amake test=0Amake install=0Amake clean=0A=0A... or running it = directly from /home/smtpd/qpsmtpd?=0A=0APresently I'm running ./qpsmtpd fro= m xinetd, so the installed copy is probably wasted, right?=0A=0AIs there an= y benefit/downside in running an installed copy, and how would I do that?= =0A=0AHans=0A=0A=0A There is no benefit to installing. I've been running under xinetd for a couple of years, directly from an svn checkout in /var/qpsmtpd. In fact, I dont even make changes ...

XE2 update 2: Installer still install some files you dont ask for
I´m testing a new IntraWeb XII installer on a VM and I choose to not install IntraWeb from the XE2 installer, but it still adds a lot of IW files to the XE2 install. Any way to fix it? -- Jackson Gomes - IntraWeb Support http://www.atozed.com/intraweb Blog: http://www.atozed.com/intraweb/blog Download: http://www.atozed.com/intraweb/download That reminds me of Blackfish SQL. It was impossible not to install it... Same story with BDE. It gets installed you want it or not. On 2011-11-06 14:50:26 -0500, Jackson Gomes <jackson@toolsandcomps.com> said: > I´...

Install D2010 on side of D2009
I am installing D2010 from the iso image. But the setup complains that I should install Update 3 for D2009 before that. However, D2009 Check for Updates said that no updates were available, so I copied the setup packages from another D2009 installation and installed Update 3, 4, etc. And D2010 installation still fails to start, complaining that I should install Update 3 to D2009. How can I tell the installer that I DO have Update 3 for D2009? Jouni Aro Prosys I have the same problem. BDS 2009 is up to date with Version3, but Delphi 2010 will not install because it claim...

installed version not updated after install
--============_-1187831132==_ma============ Content-Type: text/plain; charset="us-ascii" ; format="flowed" For a few modules, the CPAN_VERSION and INST_VERSION reported by the i CPAN command disagree, even after I apparently successfully installed/updated a module. Can someone explain what's going on here? For instance [Perl 2.6.1, Mac OS 10.1.5], here's the CPAN output for Net::Ping. (The same thing happens with Storable, where CPAN_VERSION is 2.04 but INST_VERSION is 1.014 even after apparently successfully installing Storable 2.04.) And what&#...

install 11.9.2 exception access violation
I can see there is an old entry about this problem. "-INS0432_MP.EXE" "Exception access violation (0xc0000005),Address: 0x6e65696c" I have a win2K /fp4 platform and trying to install sybase 11.9.2 and getting the same problem. In other forums I could see many people complaining about this with installation of other prodcuts. Any idea this can be Thanks for all help/info Regards, Guy Przytula ...

Tomcat installation failing during iManager 2.0.2 install
I'm trying to install iManager with default Tomcat server, the Tomcat installation fails with following error Unhandled Exception c0000005 access violation at address 500bf974 I was able to install iManager successfully on couple of other pcs. Thx Hi, I think you may have some faulty ram ..... John >>> <deepakg@interrait.com> 03/12/2004 >>> I'm trying to install iManager with default Tomcat server, the Tomcat installation fails with following error Unhandled Exception c0000005 access violation at address 500bf974 I was able to in...

Install PB 10 update without needing to install PB 9 update, then PB 8 update....
We have a bunch of updates to PB. Is there a way we can install PB 10 without needing to install all the previous versions of PB? If all you have is an update version, then you'll need to have some previous version of PB installed. On 4 Mar 2005 05:54:11 -0800, "Daniel Coppersmith" <daniel_N.0.S.P.A.M_at_InFrontSoftware_D0T_C0M> wrote: >We have a bunch of updates to PB. Is there a way we can install PB 10 >without needing to install all the previous versions of PB? > > Bruce Armstrong [TeamSybase] http://www.teamsybase.com Vote for D...

[XE] I did not Install the Boost Libraries when I installed XE but it did not stop Update 1 Boost from Installing.
This message is in MIME format. Since your mail reader does not understand this format, some or all of this message may not be legible. --JivePart=_4a211.zeB8CwDOH5aMJzMl Content-Type: text/plain; charset="Utf-8" ?I did not Install the Boost Libraries when I installed XE but it did not stop Update 1 Boost from Installing. --JivePart=_4a211.zeB8CwDOH5aMJzMl Content-Type: image/png; name="Update 1 Boost Install.PNG" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="Update 1 Boost Install.PNG" iVBORw0KGgoAAAANSUhEUgA...

[XE] I did not Install the Boost Libraries when I installed XE but it did not stop Update 1 Boost from Installing.
?[XE] I did not Install the Boost Libraries when I installed XE but it did not stop Update 1 Boost from Installing. Should I report this as a problem in QC? ( See public.attachements ) Larry ...

Update 2 11.2 installs with dial-up?
I have a Pentium3 & P4 with fresh 11.2 installs. Can I capture the update files from one to be used on the other? These boxes aren't connected together, but each has an unused LAN card if that would help. Each box has a 56K modem that runs about 40K! I haven't started the update process yet, so I don't know if there any new options to the SW Management tools in 11.2. Is this a pipe dream? Heboland. -- heboland ------------------------------------------------------------------------ heboland;2137333 Wrote: > I have a Pentium3 & P4 with fresh 11.2...

The update manager failed to install an update. #2
Name: Xander Email: oxpatchrebatgmaildotcom Product: Firefox Release Candidate Summary: The update manager failed to install an update. Comments: I have a screen shot with the dialog boxes showing the error messages. The program updater.exe has encountered a problem and needs to close. We are sorry for the inconvenience. I was running FFv2 and this became a problem. I tried several remedies from your website and message boards but nothing worked. I downloaded and installed FFv3b5 and it worked fine (except for some bugs with Yuku mess boards) until this am when it tri...

10.2.2 update not installed correctly
I have a problem with upgrading zcm from 10.2.0 to 10.2.2 The 10.2.2 update downloaded normally, but when I tried to install the update on our *1 Windows 2003 primary server* it kept saying (I'm paraphrasing from memory) "An unknown error has occurred, check the update log for more details." Well the update log was not being created. All of the other updates had multiple log files in their respective log directories. So I tried multiple things to get it to install, including: deleting and re-downloading it, downloading it manually importing it, setting the log le...

Web resources about - Access Violation after Update 2 installed - embarcadero.cppbuilder.install

CP violation - Wikipedia, the free encyclopedia
In particle physics , CP violation (CP standing for Charge Parity ) is a violation of the postulated CP-symmetry (or Charge conjugation Parity ...

Microsoft Attacks Google for Privacy violations - Flickr - Photo Sharing!
Explore MichalSpocko's photos on Flickr. MichalSpocko has uploaded 24 photos to Flickr.

Rep. Luis V. Gutierrez Denounces Civil Rights Violations in Puerto Rico - YouTube
February 16, 2011 - Rep. Luis V. Gutierrez (IL-4) spoke out against the Puerto Rican government's campaign to silence student protestors and ...

Gul defies Erdogan’s Twitter ban and calls move ‘violation of rights’
The content of Abdullah Gul’s message – and the way it was delivered – is a message to Recep Tayyip Erdogan’s religiously conservative government, ...

Russia closes 12 McDonald's restaurants over hygiene violations
Russia has temporarily closed 12 branches of McDonald's on health grounds and is carrying out more than 100 inspections, the US fast food chain ...

William sees red over second paparazzi violation
William sees red over second paparazzi violation

Report alleges labour violations at Apple supplier in China
Report claims dangerous conditions, labour violations at another Apple plant.

'Violation and betrayal': Low pay offer hurt ADF's fighting edge, say ADFA academics
Miserly pay approach potential threat to 'operational success', academics argue.

Nick Kyrgios issued code violation at Japan Open - The Courier-Mail Search Search
NICK Kyrgios has hit out at the Australian media following his loss to Frenchman Benoit Paire at the Japan Open on the weekend.

Nick Kyrgios issued code violation at Japan Open
NICK Kyrgios has hit out at the Australian media following his loss to Frenchman Benoit Paire at the Japan Open on the weekend.

Resources last updated: 12/3/2015 12:48:26 AM