Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: c++builder XE, deadlock in TThread::Synchronize()


This question is answered.


Permlink Replies: 6 - Last Post: Sep 29, 2014 2:18 AM Last Post By: chen zero
chen zero

Posts: 30
Registered: 5/26/00
c++builder XE, deadlock in TThread::Synchronize()  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 28, 2014 12:39 AM
Hello,
I posted a test project in:
https://forums.embarcadero.com/thread.jspa?threadID=108761&stqc=true

C++Builder XE
WinXP

please refer to the code of test project.

more test threads running, more easy to encounter deadlock when clicking Button2
(I meant the "deadlock" ---- Button2 was down and the whole UI was not responsible,
sometimes, it's not easy to reproduce, however, when test threads reach to 150-300,
it's easy to encounter this "deadlock" when clicking Button2 quickly)

could you help on this ?
Thanks!
Antonio Estevez

Posts: 665
Registered: 4/12/00
Re: c++builder XE, deadlock in TThread::Synchronize() [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 28, 2014 2:49 AM   in response to: chen zero in response to: chen zero
El 28/09/14 09:59, chen zero escribió:
Hello,
I posted a test project in:
https://forums.embarcadero.com/thread.jspa?threadID=108761&stqc=true

C++Builder XE
WinXP

please refer to the code of test project.

more test threads running, more easy to encounter deadlock when clicking Button2
(I meant the "deadlock" ---- Button2 was down and the whole UI was not responsible,
sometimes, it's not easy to reproduce, however, when test threads reach to 150-300,
it's easy to encounter this "deadlock" when clicking Button2 quickly)

could you help on this ?
Thanks!

I think that the deadlock is produced by the critical section of the
SharedObj object.

Why are you protecting the call to TTread::Synchronize with a critical
section?

Try with something like this:

class SharedObj
{
protected:
	void __fastcall sync() {
		if (someData!= oldData) {
			Form1->Caption = IntToStr(someData);
			Form1->Memo1->Text = "the current data val: " + IntToStr(someData);
			oldData= someData;
		}
	}
 
public:
	int oldData;
	int someData;
 
	SharedObj() {
		someData= 0;
		oldData= -1;
	}
	virtual __fastcall ~SharedObj() {
	}
 
	void __fastcall tick() {
			someData++;
			TThread::Synchronize(NULL, sync);
	}
};
chen zero

Posts: 30
Registered: 5/26/00
Re: c++builder XE, deadlock in TThread::Synchronize() [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 28, 2014 3:16 AM   in response to: Antonio Estevez in response to: Antonio Estevez
Antonio Estevez wrote:
El 28/09/14 09:59, chen zero escribió:
...

I think that the deadlock is produced by the critical section of the
SharedObj object.
yes, the deadlock is occurred when exuecting TCriticalSection.Enter();
there are some race in TCriticalSection.Enter() and TThread::Synchronize


Why are you protecting the call to TTread::Synchronize with a critical
section?
The CriticalSection is to protecte shared data in multi thread, in this app, SharedObj.someData.
the reason of TThread::Synchronize is also in cirtial section, this is because I want the UI to show the CURRENT value.
If the TTread::Synchronize is not in critical section, I am afraid that
it will show some inconsistent state in a more complex shared object.


Try with something like this:

class SharedObj
{
protected:
	void __fastcall sync() {
		if (someData!= oldData) {
			Form1->Caption = IntToStr(someData);
			Form1->Memo1->Text = "the current data val: " + IntToStr(someData);
			oldData= someData;
		}
	}
 
public:
	int oldData;
	int someData;
 
	SharedObj() {
		someData= 0;
		oldData= -1;
	}
	virtual __fastcall ~SharedObj() {
	}
 
	void __fastcall tick() {
			someData++;
			TThread::Synchronize(NULL, sync);
	}
};

Thanks, but I think it still needs TCriticalSection for shared object in multi threads.

Edited by: chen zero on Sep 28, 2014 3:36 AM
Antonio Estevez

Posts: 665
Registered: 4/12/00
Re: c++builder XE, deadlock in TThread::Synchronize()
Correct
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 28, 2014 3:40 AM   in response to: chen zero in response to: chen zero
chen zero wrote:
Antonio Estevez wrote:
El 28/09/14 09:59, chen zero escribió:
...

I think that the deadlock is produced by the critical section of the
SharedObj object.
yes, the deadlock is occurred when exuecting TCriticalSection.Enter();
there are some race in TCriticalSection.Enter() and TThread::Synchronize

TThread::Synchronize uses a TMonitor object to serialize calls to the function passed as parammeter and that only one thread can access the main thread



Why are you protecting the call to TTread::Synchronize with a critical
section?
This is because I want the UI to show the CURRENT value.
If the TTread::Synchronize is not in critical section, I am afraid that
it will show some inconsistent state in a more complex shared object.

Then protect only the block of code where you are reading/modifying the data:

class SharedObj
{
protected:
	void __fastcall sync() {
		lock->Enter();
		try {
			Form1->Caption = IntToStr(someData);
			Form1->Memo1->Text = "the current data val: " + IntToStr(someData);
		}
		__finally {
			lock->Leave();
		}
	}
 
public:
	int someData;
	TCriticalSection* lock;
 
	SharedObj() {
		someData= 0;
		lock = new TCriticalSection();
	}
	virtual __fastcall ~SharedObj() {
		delete lock;
	}
 
	void __fastcall tick() {
		lock->Enter();
		try {
			someData++;
		}
		__finally {
			lock->Leave();
		}
		TThread::Synchronize(NULL, sync);
	}
};


Thanks, but I think it still needs TCriticalSection for shared object in multi threads.
chen zero

Posts: 30
Registered: 5/26/00
Re: c++builder XE, deadlock in TThread::Synchronize()  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 28, 2014 5:06 AM   in response to: Antonio Estevez in response to: Antonio Estevez
Antonio Estevez wrote:
chen zero wrote:
Antonio Estevez wrote:
El 28/09/14 09:59, chen zero escribió:
...

I think that the deadlock is produced by the critical section of the
SharedObj object.
yes, the deadlock is occurred when exuecting TCriticalSection.Enter();
there are some race in TCriticalSection.Enter() and TThread::Synchronize

TThread::Synchronize uses a TMonitor object to serialize calls to the function passed as parammeter and that only one thread can access the main thread



Why are you protecting the call to TTread::Synchronize with a critical
section?
This is because I want the UI to show the CURRENT value.
If the TTread::Synchronize is not in critical section, I am afraid that
it will show some inconsistent state in a more complex shared object.

Then protect only the block of code where you are reading/modifying the data:

class SharedObj
{
protected:
	void __fastcall sync() {
		lock->Enter();
		try {
			Form1->Caption = IntToStr(someData);
			Form1->Memo1->Text = "the current data val: " + IntToStr(someData);
		}
		__finally {
			lock->Leave();
		}
	}
 
public:
	int someData;
	TCriticalSection* lock;
 
	SharedObj() {
		someData= 0;
		lock = new TCriticalSection();
	}
	virtual __fastcall ~SharedObj() {
		delete lock;
	}
 
	void __fastcall tick() {
		lock->Enter();
		try {
			someData++;
		}
		__finally {
			lock->Leave();
		}
		TThread::Synchronize(NULL, sync);
	}
};


Antonio, thanks!. I tried your code and it never dead lock. but I really can not see big difference, becuase, in your code,
when code to access VCL object,
Form1->Caption = "the current data val: " + IntToStr(someData);
....
the lock is stilled locked.

in my code, the lock is locked by a Test thread, but not in main thread
why my code dead lock ?

after rethink, I got the point. the main-thread will try to enter a CS accuired by another thread, and that thread waits for the main-thread to sync.
dead lock!

Thanks!

Edited by: chen zero on Sep 28, 2014 5:12 AM
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: c++builder XE, deadlock in TThread::Synchronize() [Edit]
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 28, 2014 9:58 AM   in response to: Antonio Estevez in response to: Antonio Estevez
Antonio wrote:

Then protect only the block of code where you are reading/modifying
the data:

You should not keep the lock while accessing the UI. Obtain the lock long
enough to grab the new value, then unlock and use the value as needed. For
example:

class SharedObj
{
protected:
    void __fastcall sync() {
        int newData;
        lock->Enter();
        try {
            newData = someData;
        }
        __finally {
            lock->Leave();
        }
        Form1->Caption = IntToStr(newData);
        Form1->Memo1->Text = "the current data val: " + IntToStr(newData);
    }
    ...
};


With that said, for this specific example, I would suggest using TInterlocked
and TThread::Queue() instead:

class SharedObj
{
protected:
    void __fastcall sync() {
        int newData = TInterlocked::Add(someData, 0);
        Form1->Caption = IntToStr(newData);
        Form1->Memo1->Text = "the current data val: " + IntToStr(newData);
    }
 
public:
    int someData;
    SharedObj() {
        someData= 0;
    }
    void __fastcall tick() {
        TInterlocked::Increment(someData);
        TThread::Queue(NULL, sync);
    }
};


--
Remy Lebeau (TeamB)
chen zero

Posts: 30
Registered: 5/26/00
Re: c++builder XE, deadlock in TThread::Synchronize() [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 29, 2014 2:18 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy, Thanks for the idea and demo of the new API
The multi threads apps are really subtle and not easy to be correct ...
Regards
chenzero

Remy Lebeau (TeamB) wrote:
... ...
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02