Thread synchronization and GUI

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Post Reply
mark_c
BCBJ Master
BCBJ Master
Posts: 249
Joined: Thu Jun 21, 2012 1:13 am

Thread synchronization and GUI

Post by mark_c »

Hello,
I'm struggling with an old educational project for the study of synchronization, I do not understand why in this case there is no collision!
In my opinion, it should be there when Thread1 writes to the StringGrid: am I wrong?

Thank you

Code: Select all

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

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"

class TMyThread1 : public TThread
{
protected:
	void __fastcall Execute();
public:
	__fastcall TMyThread1();
	void __fastcall MySincrSock1();
	String msg;
};

TMyThread1 *Thread1 = NULL;


//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
	ServerSocket1->Port = 5000;
	ServerSocket1->Active = true;
}
//---------------------------------------------------------------------------

__fastcall TMyThread1::TMyThread1()
: TThread(true)
{
}
//---------------------------------------------------------------------------

void __fastcall TMyThread1::MySincrSock1()
{
	try{
		for(int actconn = 0; actconn < Form1->ServerSocket1->Socket->ActiveConnections; actconn++)
		{
			Form1->ServerSocket1->Socket->Connections[actconn]->SendText(msg);
			Form1->Caption="1";
		}

	} catch(...) { }
}
//---------------------------------------------------------------------------

void __fastcall TMyThread1::Execute()
{
	while (!Terminated)
	{
		for(int i=0; i<10;i++)
		{
			msg.sprintf("Y27.5,1,192.168.1.%d,5694,25,25,127",i);
			Synchronize(&MySincrSock1);

                        Form1->StringGrid1->Cells[1][i]=msg;
			Sleep(100);
			Form1->StringGrid1->Cells[1][i]="";
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
	delete Thread1;

	ServerSocket1->Active = false;
        
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	Thread1 = new TMyThread1();

	Button1->Enabled = false;
	Button2->Enabled = true;

	Caption = "Started.....";

	Thread1->Resume();        
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
	if (Thread1) Thread1->Terminate();

	Button1->Enabled = true;
	Button2->Enabled = false;

	Caption = "Stopped.....";        
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ServerSocket1ClientError(TObject *Sender,
      TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
	Socket->Close();
	ErrorCode = 0;        
}
//---------------------------------------------------------------------------
mark_c
BCBJ Master
BCBJ Master
Posts: 249
Joined: Thu Jun 21, 2012 1:13 am

Re: Thread synchronization and GUI

Post by mark_c »

finally with this version I can experience a collision: apparently a single thread, the previous version of the code, is not enough to cause a collision or, it can happen a collision but in a non-deterministic time

Code: Select all

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

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"

class TMyThread1 : public TThread
{
protected:
	void __fastcall Execute();
public:
	__fastcall TMyThread1();
	void __fastcall MySincrSock1();
	String msg;
};


class TMyThread2 : public TThread
{
protected:
	void __fastcall Execute();
public:
	__fastcall TMyThread2();
	void __fastcall MySincrSock2();
	String msg;
};

TMyThread1 *Thread1 = NULL;
TMyThread2 *Thread2 = NULL;

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
	ServerSocket1->Port = 5000;
	ServerSocket1->Active = true;

	ServerSocket2->Port = 5001;
	ServerSocket2->Active = true;
}
//---------------------------------------------------------------------------

__fastcall TMyThread1::TMyThread1()
: TThread(true)
{
}
//---------------------------------------------------------------------------

__fastcall TMyThread2::TMyThread2()
: TThread(true)
{
}
//---------------------------------------------------------------------------

void __fastcall TMyThread1::MySincrSock1()
{
	try{
		for(int actconn = 0; actconn < Form1->ServerSocket1->Socket->ActiveConnections; actconn++)
		{
			Form1->ServerSocket1->Socket->Connections[actconn]->SendText(msg);
			Form1->Caption="1";
		}

	} catch(...) { }
}
//---------------------------------------------------------------------------

void __fastcall TMyThread2::MySincrSock2()
{
	try{
		for(int actconn = 0; actconn < Form1->ServerSocket2->Socket->ActiveConnections; actconn++)
		{
			Form1->ServerSocket2->Socket->Connections[actconn]->SendText(msg);
			Form1->Caption="2";
		}

	} catch(...) { }
}
//---------------------------------------------------------------------------

void __fastcall TMyThread1::Execute()
{
	while (!Terminated)
	{
		for(int i=0; i<10;i++)
		{
			msg.sprintf("Y27.5,1,192.168.1.%d,5694,25,25,127",i);
			Synchronize(&MySincrSock1);

                        Form1->StringGrid1->Cells[1][i]=msg;
			Sleep(100);
			Form1->StringGrid1->Cells[1][i]="";
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TMyThread2::Execute()
{
	while (!Terminated)
	{
		for(int i=0; i<10;i++)
		{
			msg.sprintf("Y27.5,1,192.168.1.%d,5694,25,25,127",i);
			Synchronize(&MySincrSock2);

                        Form1->StringGrid1->Cells[1][i]=msg;
			Sleep(100);
			Form1->StringGrid1->Cells[1][i]="";
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
	delete Thread1;
        delete Thread2;

	ServerSocket1->Active = false;
        ServerSocket2->Active = false;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	Thread1 = new TMyThread1();
        Thread2 = new TMyThread2();

	Button1->Enabled = false;
	Button2->Enabled = true;

	Caption = "Started.....";

	Thread1->Resume();
        Thread2->Resume();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
	if (Thread1) Thread1->Terminate();
        if (Thread2) Thread2->Terminate();

	Button1->Enabled = true;
	Button2->Enabled = false;

	Caption = "Stopped.....";        
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ServerSocket1ClientError(TObject *Sender,
      TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
	Socket->Close();
	ErrorCode = 0;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ServerSocket2ClientError(TObject *Sender,
      TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
	Socket->Close();
	ErrorCode = 0;
}
//---------------------------------------------------------------------------
mark_c
BCBJ Master
BCBJ Master
Posts: 249
Joined: Thu Jun 21, 2012 1:13 am

Re: Thread synchronization and GUI

Post by mark_c »

Hello,
but is it possible to declare and implement the shared methods only once so they can be used by multiple threads?

the method below, for example, is very inconvenient.

Code: Select all

class TMyThread1 : public TThread
{
protected:
	void __fastcall Execute();
public:
	__fastcall TMyThread1();
	void __fastcall MySincrSock();
        void __fastcall MyStringGrid();
	String msg;
        int i;
};


class TMyThread2 : public TThread
{
protected:
	void __fastcall Execute();
public:
	__fastcall TMyThread2();
	void __fastcall MySincrSock();
        void __fastcall MyStringGrid();
	String msg;
        int i;
};

void __fastcall TMyThread1::MyStringGrid()
{
        Form1->StringGrid1->Cells[1][i]=msg;
        if(i > 0)
        Form1->StringGrid1->Cells[1][i-1]="";
}
//---------------------------------------------------------------------------

void __fastcall TMyThread2::MyStringGrid()
{
        Form1->StringGrid1->Cells[1][i]=msg;
        if(i > 0)
        Form1->StringGrid1->Cells[1][i-1]="";
}
//---------------------------------------------------------------------------

[b]void __fastcall TMyThread(n)::MyStringGrid()[/b]
{
        Form1->StringGrid1->Cells[1][i]=msg;
        if(i > 0)
        Form1->StringGrid1->Cells[1][i-1]="";
}
//---------------------------------------------------------------------------
rlebeau
BCBJ Author
BCBJ Author
Posts: 1739
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: Thread synchronization and GUI

Post by rlebeau »

mark_c wrote:but is it possible to declare and implement the shared methods only once so they can be used by multiple threads?
Simply use a single thread class. Your multiple classes are doing the exact same thing, and thus are completely redundant. Just create multiple object instances of the same class.

Code: Select all

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

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"

class TMyThread : public TThread
{
protected:
	void __fastcall Execute();
public:
	__fastcall TMyThread(int ANum, TServerSocket *AServer);
	void __fastcall MySincrSock();
	String msg;
	int num;
	TServerSocket *server;
};

TMyThread *Thread1 = NULL;
TMyThread *Thread2 = NULL;

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
	ServerSocket1->Port = 5000;
	ServerSocket1->Active = true;

	ServerSocket2->Port = 5001;
	ServerSocket2->Active = true;
}
//---------------------------------------------------------------------------

__fastcall TMyThread::TMyThread(int ANum, TServerSocket *AServer)
	: TThread(true)
{
	num = ANum;
	server = AServer;
}
//---------------------------------------------------------------------------

void __fastcall TMyThread::MySincrSock()
{
	try{
		for(int actconn = 0; actconn < server->Socket->ActiveConnections; actconn++)
		{
			server->Socket->Connections[actconn]->SendText(msg);
			Form1->Caption = num;
		}

	} catch(...) { }
}
//---------------------------------------------------------------------------

void __fastcall TMyThread::Execute()
{
	while (!Terminated)
	{
		for(int i = 0; i < 10; i++)
		{
			msg.sprintf("Y27.5,1,192.168.1.%d,5694,25,25,127",i);
			Synchronize(&MySincrSock);

			Form1->StringGrid1->Cells[1][i]=msg;
			Sleep(100);
			Form1->StringGrid1->Cells[1][i]="";
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
	delete Thread1;
	delete Thread2;

	ServerSocket1->Active = false;
	ServerSocket2->Active = false;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	Thread1 = new TMyThread(1, ServerSocket1);
	Thread2 = new TMyThread(2, ServerSocket2);

	Button1->Enabled = false;
	Button2->Enabled = true;

	Caption = "Started.....";

	Thread1->Resume();
	Thread2->Resume();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
	if (Thread1) Thread1->Terminate();
	if (Thread2) Thread2->Terminate();

	Button1->Enabled = true;
	Button2->Enabled = false;

	Caption = "Stopped.....";       
}
//---------------------------------------------------------------------------
// you can assign this one handler to BOTH TServerSocket objects!
void __fastcall TForm1::ServerSocketClientError(TObject *Sender,
      TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
	Socket->Close();
	ErrorCode = 0;
}
//---------------------------------------------------------------------------
Remy Lebeau (TeamB)
Lebeau Software
mark_c
BCBJ Master
BCBJ Master
Posts: 249
Joined: Thu Jun 21, 2012 1:13 am

Re: Thread synchronization and GUI

Post by mark_c »

thanks remy, forgive my curiosity: but are you a teacher?
rlebeau
BCBJ Author
BCBJ Author
Posts: 1739
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: Thread synchronization and GUI

Post by rlebeau »

mark_c wrote:thanks remy, forgive my curiosity: but are you a teacher?
No, I am not. I am a professional software developer.
Remy Lebeau (TeamB)
Lebeau Software
Post Reply