Trap socket error 10055

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Re: Trap socket error 10055

Postby mark_c » Tue Jan 14, 2020 11:42 pm

Yes Remy, true what you say. I noticed that programming and playing the piano are two very similar activities: if you don't keep practicing and reviewing what you know, you forget everything.
Anyway I solved the problem as you say too and that is instantiating 100 classes with 100 threads and 100 sockets but my problem now lies in the initialization of the 100 threads as, I am using a global variable that creates problems for me for the usual race condition problem .
This is a portion of the program with the problem.

The purpose of this part of the code is only to understand the initialization of the 100 threads through a global variable. As you can see, I have not used semaphores but a sm variable that blocks the creation of the other threads to prevent the myadr variable from being overwritten by the creation of other threads.

Code: Select all
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"

class TMyThread : public TThread
{
protected:
   void __fastcall Execute();
public:
   __fastcall TMyThread();
};

TMyThread *TMyTh[100];
AnsiString myadr;

bool sm;

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------

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

void __fastcall TMyThread::Execute()
{
   BOOL bErrorFlag = FALSE;
   DWORD dwBytesWritten;

   HANDLE hFile;

   AnsiString fname = "dirout\\" + myadr + ".txt";
        AnsiString msg;

   hFile = CreateFile(fname.c_str(),
                           GENERIC_WRITE,
                           FILE_SHARE_WRITE,
                           NULL,
                           CREATE_ALWAYS,
                           FILE_ATTRIBUTE_NORMAL,
                           NULL);
        sm=false;

        msg = myadr;

   bErrorFlag = WriteFile( hFile,
                                msg.c_str(),
                                msg.Length(),
                                &dwBytesWritten,
                                NULL);

   CloseHandle(hFile);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
   for(int i = 0; i<100; i++)   {

      myadr = "adr_" + IntToStr(i+1);
      TMyTh[i] = new TMyThread();
      TMyTh[i]->Resume();

                sm=true;
                while(sm);
   }

   Caption="created";

   for(int i = 0; i<1000; i++)
   {
      if (TMyTh[i])
                        TMyTh[i]->Terminate();
   }

        Caption="Terminated";
}
//---------------------------------------------------------------------------

mark_c
BCBJ Master
BCBJ Master
 
Posts: 203
Joined: Thu Jun 21, 2012 1:13 am

Re: Trap socket error 10055

Postby rlebeau » Wed Jan 15, 2020 11:48 am

mark_c wrote:my problem now lies in the initialization of the 100 threads as, I am using a global variable that creates problems for me for the usual race condition problem.


Don't use globals to pass values into your threads. Add parameters to your Thread's constructor instead, eg:

Code: Select all
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"

class TMyThread : public TThread
{
private:
   AnsiString myadr;
protected:
   void __fastcall Execute();
public:
   __fastcall TMyThread(const AnsiString &Adr);
};

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
   : TForm(Owner)
{
}
//---------------------------------------------------------------------------

__fastcall TMyThread::TMyThread(const AnsiString &Adr)
   : TThread(false), myadr(Adr)
{
}
//---------------------------------------------------------------------------

void __fastcall TMyThread::Execute()
{
   AnsiString fname = "dirout\\" + myadr + ".txt";

   HANDLE hFile = CreateFileA(fname.c_str(),
                           GENERIC_WRITE,
                           FILE_SHARE_WRITE,
                           NULL,
                           CREATE_ALWAYS,
                           FILE_ATTRIBUTE_NORMAL,
                           NULL);
   if (hFile != INVALID_HANDLE_VALUE)
   {
      DWORD dwBytesWritten;
      WriteFile( hFile,
                                myadr.c_str(),
                                myadr.Length(),
                                &dwBytesWritten,
                                NULL);

      CloseHandle(hFile);
   }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
   TMyThread* TMyTh[100] = {};
   HANDLE hTh[100] = {};
   DWORD NumThreads = 0;

   try
   {
      for(int i = 0; i < 100; ++i) {
         TMyTh[i] = new TMyThread("adr_" + IntToStr(i+1));
         ++NumThreads;
         hTh[i] = reinterpret_cast<HANDLE>(TMyTh[i]->Handle);
      }

      Caption = "created";

      do
      {
         DWORD dwRet = MsgWaitForMultipleObjects(NumThreads, hTh, FALSE, INFINITE, QS_ALLINPUT);
         if (dwRet == WAIT_FAILED)
            RaiseLastOSError();

         else if ((dwRet >= WAIT_OBJECT_0) && (dwRet < (WAIT_OBJECT_0+count)))
         {
            DWORD dwIndex = dwRet - WAIT_OBJECT_0;

            delete TMyTh[dwIndex];
            for(DWORD i = dwIndex + 1; i < NumHandles; ++i) {
               TMyTh[i-1] = TMyTh[i];
               hTh[i-1] = hTh[i];
            }

            --NumThreads;
         }

         else if (dwRet == (WAIT_OBJECT_0+count))
            Application->ProcessMessages();
      }
      while (NumThreads > 0);

      Caption = "Terminated";
   }
   __finally
   {
      for(DWORD i = 0; i < NumThreads; ++i) {
         delete TMyTh[i];
      }
   }
}
//---------------------------------------------------------------------------



Alternatively:

Code: Select all
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"

class TMyThread : public TThread
{
private:
   AnsiString myadr;
protected:
   void __fastcall Execute();
public:
   __fastcall TMyThread(const AnsiString &Adr);
};

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
int ThreadsRunning = 0;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
   : TForm(Owner)
{
}
//---------------------------------------------------------------------------

__fastcall TMyThread::TMyThread(const AnsiString &Adr)
   : TThread(true), myadr(Adr)
{
   FreeOnTerminate = true;
}
//---------------------------------------------------------------------------

void __fastcall TMyThread::Execute()
{
   AnsiString fname = "dirout\\" + myadr + ".txt";

   HANDLE hFile = CreateFileA(fname.c_str(),
                           GENERIC_WRITE,
                           FILE_SHARE_WRITE,
                           NULL,
                           CREATE_ALWAYS,
                           FILE_ATTRIBUTE_NORMAL,
                           NULL);
   if (hFile != INVALID_HANDLE_VALUE)
   {
      DWORD dwBytesWritten;
      WriteFile( hFile,
                                myadr.c_str(),
                                myadr.Length(),
                                &dwBytesWritten,
                                NULL);

      CloseHandle(hFile);
   }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
   for(int i = 0; i < 100; ++i) {
      TMyTh[i] = new TMyThread("adr_" + IntToStr(i+1));
      TMyTh[i]->OnTerminate = &ThreadTerminated;
      TMyTh[i]->Resume();
      ++ThreadsRunning;
   }

   Caption = "created";
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ThreadTerminated(TObject *Sender)
{
   ++ThreadsRunning;
   if (ThreadsRunning == 0)
      Caption = "Terminated";
}
//---------------------------------------------------------------------------

Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1649
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Trap socket error 10055

Postby mark_c » Thu Jan 16, 2020 5:12 am

thanks Remy, as always.
If I understand your idea, your piece of code that I paste again, it has the function of freeing up the resources of the various threads when they naturally end their life cycle, right?

Code: Select all

do
      {
         DWORD dwRet = MsgWaitForMultipleObjects(NumThreads, hTh, FALSE, INFINITE, QS_ALLINPUT);

         if (dwRet == WAIT_FAILED)
                        {
                 RaiseLastOSError();
                        }
         else if ((dwRet >= WAIT_OBJECT_0) && (dwRet < (WAIT_OBJECT_0+NumThr)))
         {
            DWORD dwIndex = dwRet - WAIT_OBJECT_0;

            delete TMyTh[dwIndex];
            for(DWORD i = dwIndex + 1; i < NumThr; ++i) {
               TMyTh[i-1] = TMyTh[i];
               hTh[i-1] = hTh[i];
            }

            --NumThreads;
         }

         else if (dwRet == (WAIT_OBJECT_0+NumThr))
         Application->ProcessMessages();
      }
      while (NumThreads > 0);
mark_c
BCBJ Master
BCBJ Master
 
Posts: 203
Joined: Thu Jun 21, 2012 1:13 am

Re: Trap socket error 10055

Postby rlebeau » Fri Jan 17, 2020 11:44 am

mark_c wrote:If I understand your idea, your piece of code that I paste again, it has the function of freeing up the resources of the various threads when they naturally end their life cycle, right?


Yes, the purpose of that loop is to wait for all of the threads to finish their work, freeing each thread as it finishes, while also servicing the main UI message queue since the loop blocks the main UI message loop. Of course, it is not a good idea to block the main UI message loop, which is why I also gave you the alternative approach that uses the TThread::OnTerminate event and TThread::FreeOnTerminate property instead.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1649
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Trap socket error 10055

Postby mark_c » Sat Jan 18, 2020 5:44 am

sorry for the useless post, but I think I had an idea
mark_c
BCBJ Master
BCBJ Master
 
Posts: 203
Joined: Thu Jun 21, 2012 1:13 am

Re: Trap socket error 10055

Postby mark_c » Sat Jan 18, 2020 11:37 am

thanks Remy, you are truly a very valuable help.
I use this 3d to ask you: in the case of blocking sockets, is it correct to use this loop to read incoming messages, or do you have to use a different technique?

You taught me that code for non-blocking sockets, but now we are in the case of blocking sockets.

This is my solution but there is some problems.

Code: Select all
void __fastcall TMyThread::Execute()
{

   wile(1)
   {
      int ByteReceived;
      int Size = ClientSocket1->Socket->ReceiveLength();
      
      char *Buf = new char[Size];
      do
      {
         ByteReceived = ClientSocket1->Socket->ReceiveBuf(Buf, Size);         
         if (ByteReceived <= 0) break;         
         MyBuffer+=AnsiString(Buf, ByteReceived);         
         Size -= ByteReceived;
      }
      while( Size > 0 );

      delete []Buf;
      if( MyBuffer.Pos("\r\n\r\n") != 0 ) break;
      if( WSAGetLastError() != 0 ) break;
   }
}
mark_c
BCBJ Master
BCBJ Master
 
Posts: 203
Joined: Thu Jun 21, 2012 1:13 am

Previous

Return to Technical

Who is online

Users browsing this forum: No registered users and 13 guests

cron