BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Is the Invalidate() Method of a TControl (as TMemo) safe thr

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (VCL Components Usage)
View previous topic :: View next topic  
Author Message
Jeti
Guest





PostPosted: Tue Mar 22, 2005 2:53 pm    Post subject: Is the Invalidate() Method of a TControl (as TMemo) safe thr Reply with quote




In my BCB6 project, I have in addition to the main/Vcl thread,
a secondary thread that isn’t a Borland Thread
so I cannot use the Sinchronize() method of Tthread.

I want the secondary thread to log its output also on a Tmemo component of the main form.
So with the wizard help, I created and installed a new component TWriterMemo with ancestor type “Tmemo”,
and I added :
the public method Write(),
the protected member std::list<std::string> m_list;
and I Overrided the virtual method Update()

// ================== TwriterMemo.h ================

class PACKAGE TWriterMemo1 : public TMemo, public IWriter
{

protected: // User declarations
std::list<std::string> m_list;
TCriticalSection *m_cs;
public: // User declarations
void Write(const std::string msg);
virtual void __fastcall Update(void);

private:
protected:
public:
__fastcall TWriterMemo1(TComponent* Owner);
__fastcall ~TWriterMemo1();
__published:
};

// ================== TwriterMemo.cpp ================

void TWriterMemo1::Write(const std::string msg)
{
m_cs->Acquire();
m_list.push_back(msg);
m_cs->Release();
Repaint();
}

//---------------------------------------------------------------------------

void __fastcall TWriterMemo1::Update(void)
{
m_cs->Acquire();
while (!m_list.empty())
{
std::string str = m_list.front();
m_list.pop_front();
Lines->Add(str.c_str());
}
m_cs->Release();
}


Naturally the secondary thread knows my custom memo and invokes the method Write(string s) that stores the string and invalidates the component.

Is this approach correct and thread safe?
If not, could you suggest me a good soluction?

Thanks.
Jeti
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Tue Mar 22, 2005 9:18 pm    Post subject: Re: Is the Invalidate() Method of a TControl (as TMemo) safe Reply with quote




"Jeti" <massimo.jentile (AT) seleniacomms (DOT) com> wrote


Quote:
In my BCB6 project, I have in addition to the main/Vcl
thread, a secondary thread that isn't a Borland Thread
so I cannot use the Sinchronize() method of Tthread.

You can post messages to the main thread using PostMessage(), SendMessage(),
PostTheadMessage(), etc.

Quote:
I want the secondary thread to log its output also on a Tmemo
component of the main form.

You can use SendMessage() to send a custom message to the main thread,
passing it the string pointer to display.

Quote:
m_cs->Acquire();
m_list.push_back(msg);
m_cs->Release();

push_back() can potentially throw an exception. You should wrap the
Acquire() and Release() calls with exception handling to ensure that you
always release the critical section even when an error occurs.

Quote:
Repaint();

Repaint() is not thread-safe.

Quote:
void __fastcall TWriterMemo1::Update(void)

You are misusing Update(). It is meant to be used to process pending
painting messages only. Not for altering the component's contents.

Quote:
Is this approach correct and thread safe?

No on both accounts.

Quote:
If not, could you suggest me a good soluction?

You don't need a new component at all. Use a custom message instead, ie:


#define APPWM_LOG_MSG (WM_APP + 100)

void __fastcall TForm1::WndProc(TMessage &Message)
{
if( Message.MSg == APPWM_LOG_MSG )
{
Memo1->Lines->Add(reinterpret_cast<char*>(Message.LParam));
Message.Result = 1;
}
else
TForm::WndProc(Message);
}

DWORD WINAPI MyThreadFunc(LPVOID lpData)
{
//...
std::string msg = "...";
::SendMessage(Application->MainForm->Handle,
APPWM_LOG_MSG, 0, reinterpret_cast<LPARAM>(msg.c_str()));
//...
}

If you don't want to reference the VCL at all in your thread code, or if you
want to send the log messages to a different TForm, then store the target
HWND somewhere in memory that the thread code can reach, such as by wrapping
the thread in a class and using the thread's LPVOID parameter to access that
class, so that the target HWND can be a member of that class. For example:

class MyThreadClass
{
private:
HANDLE FThread;
DWORD FThreadID;
HWND FLogWnd;
CRITICAL_SECTION LogWndCS;
//...

static DWORD WINAPI ThreadFunc(LPVOID lpData);

struct CSLock
{
LPCRITICAL_SECTION lpcs;
CSLock(LPCRITICAL_SECTION cs);
~CSLock();
};

public:
MyThreadClass();
~MyThreadClass();
HWND getLogWnd();
void setLogWnd(HWND AWnd);
void LogMsg(const std::string &msg);
void Start();
//...
};

MyThreadClass::CSLock::CSLock(LPCRITICAL_SECTION cs)
: lpcs(cs)
{
::EnterCriticalSection(lpcs);
}

MyThreadClass::CSLock::~CSLock()
{
::LeaveCriticalSection(lpcs);
}

MyThreadClass::MyThreadClass()
{
InitializeCriticalSection(&LogWndCS);
FLogWnd = NULL;
//...
}

MyThreadClass::~MyThreadClass()
{
//...
DeleteCriticalSection(&LogWndCS);
}

HWND MyThreadClass::getLogWnd()
{
CSLock lock(&LogWndCS);
return FLogWnd;
}

void MyThreadClass::setLogWnd(HWND AWnd)
{
CSLock lock(&LogWndCS);
FLogWnd = AWnd;
}

void MyThreadClass::LogMsg(const std::string &msg)
{
HWND hwnd = getLogWnd();
if( hwnd != NULL )
::SendMessage(hwnd, APPWM_LOG_MSG, 0,
reinterpret_cast<LPARAM>(msg.c_str()));
}

void MyThreadClass::Start()
{
if( FThread == NULL )
FThread = ::CreateThread(NULL, 0, ThreadFunc, this, 0,
&FThreadID);
}

DWORD WINAPI MyThreadClass::ThreadFunc(LPVOID lpData)
{
MyThreadClass *pThis = static_cast<MyThreadClass*>(lpData);
//...
pThis->LogMsg("whatever");
//...
}


class TSomeForm : public TForm
{
private:
MyThreadClass Thread;
protected:
virtual void __fastcall CreateWnd();
virtual void __fastcall DestroyWnd();
//...
};

void __fastcall TForm1::CreateWnd()
{
TForm::CreateWnd();
Thread.setLogWnd(Handle);
}

void __fastcall TForm1::DestroyWnd()
{
Thread.setLogWnd(NULL);
TForm::DestroyWnd();
}


Gambit



Back to top
Jeti
Guest





PostPosted: Thu Mar 24, 2005 1:38 pm    Post subject: Re: Is the Invalidate() Method of a TControl (as TMemo) safe Reply with quote




Thanks a lot for your help, I’ll follow your suggestion at once !

Just a little info to be coherent with the subject:
is the Invalidate() method (as the Repaint) not thead-safe ?

Thanks
Jeti

Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (VCL Components Usage) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.