Thread synchronization and GUI

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Thread synchronization and GUI

Postby mark_c » Thu Feb 28, 2019 1:40 am

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 Guru
BCBJ Guru
 
Posts: 163
Joined: Thu Jun 21, 2012 1:13 am

Re: Thread synchronization and GUI

Postby mark_c » Fri Mar 01, 2019 2:59 am

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 Guru
BCBJ Guru
 
Posts: 163
Joined: Thu Jun 21, 2012 1:13 am

Re: Thread synchronization and GUI

Postby mark_c » Sat Mar 09, 2019 12:17 pm

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]="";
}
//---------------------------------------------------------------------------
mark_c
BCBJ Guru
BCBJ Guru
 
Posts: 163
Joined: Thu Jun 21, 2012 1:13 am

Re: Thread synchronization and GUI

Postby rlebeau » Wed Apr 17, 2019 12:17 pm

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
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1603
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Thread synchronization and GUI

Postby mark_c » Sat Apr 20, 2019 7:09 am

thanks remy, forgive my curiosity: but are you a teacher?
mark_c
BCBJ Guru
BCBJ Guru
 
Posts: 163
Joined: Thu Jun 21, 2012 1:13 am

Re: Thread synchronization and GUI

Postby rlebeau » Tue Apr 23, 2019 12:09 pm

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
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1603
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA


Return to Technical

Who is online

Users browsing this forum: No registered users and 18 guests

cron