Trap socket error 10055

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

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

Re: Trap socket error 10055

Post by mark_c »

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";
}
//---------------------------------------------------------------------------

rlebeau
BCBJ Author
BCBJ Author
Posts: 1715
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: Trap socket error 10055

Post by rlebeau »

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

Re: Trap socket error 10055

Post by mark_c »

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);
rlebeau
BCBJ Author
BCBJ Author
Posts: 1715
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: Trap socket error 10055

Post by rlebeau »

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

Re: Trap socket error 10055

Post by mark_c »

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

Re: Trap socket error 10055

Post by mark_c »

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;
	}
}
Post Reply