Page 1 of 1

Thread synchronization and GUI

PostPosted: Thu Feb 28, 2019 1:40 am
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;       
}
//---------------------------------------------------------------------------

Re: Thread synchronization and GUI

PostPosted: Fri Mar 01, 2019 2:59 am
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;
}
//---------------------------------------------------------------------------

Re: Thread synchronization and GUI

PostPosted: Sat Mar 09, 2019 12:17 pm
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]="";
}
//---------------------------------------------------------------------------

Re: Thread synchronization and GUI

PostPosted: Wed Apr 17, 2019 12:17 pm
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;
}
//---------------------------------------------------------------------------

Re: Thread synchronization and GUI

PostPosted: Sat Apr 20, 2019 7:09 am
by mark_c
thanks remy, forgive my curiosity: but are you a teacher?

Re: Thread synchronization and GUI

PostPosted: Tue Apr 23, 2019 12:09 pm
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.