Winsock recv() function blocking other threads












0















I’m writing a simple Windows TCP/IP server application, which only needs to communicate with one client at a time. My application has four threads:




  1. Main program which also handles transmission of data as needed.

  2. Receive incoming data thread.

  3. Listen thread to accept connection requests from the client.

  4. A ping thread which monitors everything else, and transmits heartbeat messages as needed. I realise that the latter shouldn’t really be necessary with TCP/IP, but the client application (over which I have no control) requires this.


I’ve confirmed in task manager that my application does indeed have four threads running.



I’m using blocking TCP/IP sockets, but my understanding is that they only block the calling thread – the other threads should still be allowed to execute without being blocked. However, I have encountered the following issues:




  1. If the ping thread deems the connection to have died, it calls closesocket(). However, this appears to be being blocked by the call to recv() in the receive thread.


  2. The main application is unable to transmit data while the receive thread has a call to recv() in progress.



The socket is being created via the accept() function. At this stage I’m not setting any socket options.



I've now created a simple two thread program which illustrates the problem. Without the WSA_FLAG_OVERLAPPED flag, the second thread gets blocked by the first thread, even though this would appear to be contrary to what is supposed to happen. If the WSA_FLAG_OVERLAPPED flag is set, then everything works as I would expect.



PROJECT SOURCE FILE:
====================

program Blocking;

uses
Forms,
Blocking_Test in 'Blocking_Test.pas' {Form1},
Close_Test in 'Close_Test.pas';

{$R *.res}

begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end. { Blocking }

UNIT 1 SOURCE FILE:
===================

unit Blocking_Test;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, WinSock2;

type
TForm1 = class(TForm)
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
Test_Socket: TSocket;
Test_Addr: TSockAddr;
wsda: TWSADATA; { used to store info returned from WSAStartup }

implementation

{$R *.dfm}

uses
Debugger, Close_Test;

procedure TForm1.FormShow(Sender: TObject);
const
Test_Port: word = 3804;
var
Buffer: array [0..127] of byte;
Bytes_Read: integer;
begin { TForm1.FormShow }
Debug('Main thread started');
assert(WSAStartup(MAKEWORD(2,2), wsda) = 0); { WinSock load version 2.2 }
Test_Socket := WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, nil, 0, 0{WSA_FLAG_OVERLAPPED});
assert(Test_Socket <> INVALID_SOCKET);
with Test_Addr do
begin
sin_family := AF_INET;
sin_port := htons(Test_Port);
sin_addr.s_addr := 0; { this will be filled in by bind }
end; { with This_PC_Address }
assert(bind(Test_Socket, @Test_Addr, SizeOf(Test_Addr)) = 0);
Close_Thread := TClose_Thread.Create(false); { start thread immediately }
Debug('B4 Rx');
Bytes_Read := recv(Test_Socket, Buffer, SizeOf(Buffer), 0);
Debug('After Rx');
end; { TForm1.FormShow }

end. { Blocking_Test }

UNIT 2 SOURCE FILE:
===================

unit Close_Test;

interface

uses
Classes;

type
TClose_Thread = class(TThread)
protected
procedure Execute; override;
end; { TClose_Thread }

var
Close_Thread: TClose_Thread;

implementation

uses
Blocking_Test, Debugger, Windows, WinSock2;

type
TThreadNameInfo = record
FType: LongWord; // must be 0x1000
FName: PChar; // pointer to name (in user address space)
FThreadID: LongWord; // thread ID (-1 indicates caller thread)
FFlags: LongWord; // reserved for future use, must be zero
end; { TThreadNameInfo }

var
ThreadNameInfo: TThreadNameInfo;

procedure TClose_Thread.Execute;

procedure SetName;
begin { SetName }
ThreadNameInfo.FType := $1000;
ThreadNameInfo.FName := 'Ping_Thread';
ThreadNameInfo.FThreadID := $FFFFFFFF;
ThreadNameInfo.FFlags := 0;
try
RaiseException( $406D1388, 0, sizeof(ThreadNameInfo) div sizeof(LongWord), @ThreadNameInfo );
except
end; { try }
end; { SetName }

begin { TClose_Thread.Execute }
Debug('Close thread started');
SetName;
sleep(10000); { wait 10 seconds }
Debug('B4 Close');
closesocket(Test_Socket);
Debug('After Close');
end; { TClose_Thread.Execute }

end. { Close_Test }


P.S. Since setting the WSA_FLAG_OVERLAPPED attribute has fixed the problem, I've posted the above for academic interest.










share|improve this question

























  • Can you please put the source code? recv should block only a thread where it resides. Otherwise, one connected client could block another client in a separate thread by issuing slow requests/responses.

    – karastojko
    Jan 2 at 7:38











  • OK, but it'll take a little while for me to make something small enough which just contains the relevant sections.

    – Chris Hubbard
    Jan 2 at 8:09











  • I’m still working on creating a small enough test program to list here, but in the meantime another thought has occurred to me: Can threads “own” other threads, and in so doing cause one thread to block another? My application is written in Delphi, and I’m using it’s standard TThread component.

    – Chris Hubbard
    Jan 2 at 10:13











  • @MartynA on Windows, closing a socket indeed cancels blocking operations in progress in other threads.

    – Remy Lebeau
    Jan 2 at 17:25











  • @ChrisHubbard are you, by chance, using your own critical section or mutex around blocking socket operations? Without seeing your actual code, that is the only way I can think of for this to happen. By themselves, blocking sockets do not behave the way you have described.

    – Remy Lebeau
    Jan 2 at 17:34


















0















I’m writing a simple Windows TCP/IP server application, which only needs to communicate with one client at a time. My application has four threads:




  1. Main program which also handles transmission of data as needed.

  2. Receive incoming data thread.

  3. Listen thread to accept connection requests from the client.

  4. A ping thread which monitors everything else, and transmits heartbeat messages as needed. I realise that the latter shouldn’t really be necessary with TCP/IP, but the client application (over which I have no control) requires this.


I’ve confirmed in task manager that my application does indeed have four threads running.



I’m using blocking TCP/IP sockets, but my understanding is that they only block the calling thread – the other threads should still be allowed to execute without being blocked. However, I have encountered the following issues:




  1. If the ping thread deems the connection to have died, it calls closesocket(). However, this appears to be being blocked by the call to recv() in the receive thread.


  2. The main application is unable to transmit data while the receive thread has a call to recv() in progress.



The socket is being created via the accept() function. At this stage I’m not setting any socket options.



I've now created a simple two thread program which illustrates the problem. Without the WSA_FLAG_OVERLAPPED flag, the second thread gets blocked by the first thread, even though this would appear to be contrary to what is supposed to happen. If the WSA_FLAG_OVERLAPPED flag is set, then everything works as I would expect.



PROJECT SOURCE FILE:
====================

program Blocking;

uses
Forms,
Blocking_Test in 'Blocking_Test.pas' {Form1},
Close_Test in 'Close_Test.pas';

{$R *.res}

begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end. { Blocking }

UNIT 1 SOURCE FILE:
===================

unit Blocking_Test;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, WinSock2;

type
TForm1 = class(TForm)
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
Test_Socket: TSocket;
Test_Addr: TSockAddr;
wsda: TWSADATA; { used to store info returned from WSAStartup }

implementation

{$R *.dfm}

uses
Debugger, Close_Test;

procedure TForm1.FormShow(Sender: TObject);
const
Test_Port: word = 3804;
var
Buffer: array [0..127] of byte;
Bytes_Read: integer;
begin { TForm1.FormShow }
Debug('Main thread started');
assert(WSAStartup(MAKEWORD(2,2), wsda) = 0); { WinSock load version 2.2 }
Test_Socket := WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, nil, 0, 0{WSA_FLAG_OVERLAPPED});
assert(Test_Socket <> INVALID_SOCKET);
with Test_Addr do
begin
sin_family := AF_INET;
sin_port := htons(Test_Port);
sin_addr.s_addr := 0; { this will be filled in by bind }
end; { with This_PC_Address }
assert(bind(Test_Socket, @Test_Addr, SizeOf(Test_Addr)) = 0);
Close_Thread := TClose_Thread.Create(false); { start thread immediately }
Debug('B4 Rx');
Bytes_Read := recv(Test_Socket, Buffer, SizeOf(Buffer), 0);
Debug('After Rx');
end; { TForm1.FormShow }

end. { Blocking_Test }

UNIT 2 SOURCE FILE:
===================

unit Close_Test;

interface

uses
Classes;

type
TClose_Thread = class(TThread)
protected
procedure Execute; override;
end; { TClose_Thread }

var
Close_Thread: TClose_Thread;

implementation

uses
Blocking_Test, Debugger, Windows, WinSock2;

type
TThreadNameInfo = record
FType: LongWord; // must be 0x1000
FName: PChar; // pointer to name (in user address space)
FThreadID: LongWord; // thread ID (-1 indicates caller thread)
FFlags: LongWord; // reserved for future use, must be zero
end; { TThreadNameInfo }

var
ThreadNameInfo: TThreadNameInfo;

procedure TClose_Thread.Execute;

procedure SetName;
begin { SetName }
ThreadNameInfo.FType := $1000;
ThreadNameInfo.FName := 'Ping_Thread';
ThreadNameInfo.FThreadID := $FFFFFFFF;
ThreadNameInfo.FFlags := 0;
try
RaiseException( $406D1388, 0, sizeof(ThreadNameInfo) div sizeof(LongWord), @ThreadNameInfo );
except
end; { try }
end; { SetName }

begin { TClose_Thread.Execute }
Debug('Close thread started');
SetName;
sleep(10000); { wait 10 seconds }
Debug('B4 Close');
closesocket(Test_Socket);
Debug('After Close');
end; { TClose_Thread.Execute }

end. { Close_Test }


P.S. Since setting the WSA_FLAG_OVERLAPPED attribute has fixed the problem, I've posted the above for academic interest.










share|improve this question

























  • Can you please put the source code? recv should block only a thread where it resides. Otherwise, one connected client could block another client in a separate thread by issuing slow requests/responses.

    – karastojko
    Jan 2 at 7:38











  • OK, but it'll take a little while for me to make something small enough which just contains the relevant sections.

    – Chris Hubbard
    Jan 2 at 8:09











  • I’m still working on creating a small enough test program to list here, but in the meantime another thought has occurred to me: Can threads “own” other threads, and in so doing cause one thread to block another? My application is written in Delphi, and I’m using it’s standard TThread component.

    – Chris Hubbard
    Jan 2 at 10:13











  • @MartynA on Windows, closing a socket indeed cancels blocking operations in progress in other threads.

    – Remy Lebeau
    Jan 2 at 17:25











  • @ChrisHubbard are you, by chance, using your own critical section or mutex around blocking socket operations? Without seeing your actual code, that is the only way I can think of for this to happen. By themselves, blocking sockets do not behave the way you have described.

    – Remy Lebeau
    Jan 2 at 17:34
















0












0








0








I’m writing a simple Windows TCP/IP server application, which only needs to communicate with one client at a time. My application has four threads:




  1. Main program which also handles transmission of data as needed.

  2. Receive incoming data thread.

  3. Listen thread to accept connection requests from the client.

  4. A ping thread which monitors everything else, and transmits heartbeat messages as needed. I realise that the latter shouldn’t really be necessary with TCP/IP, but the client application (over which I have no control) requires this.


I’ve confirmed in task manager that my application does indeed have four threads running.



I’m using blocking TCP/IP sockets, but my understanding is that they only block the calling thread – the other threads should still be allowed to execute without being blocked. However, I have encountered the following issues:




  1. If the ping thread deems the connection to have died, it calls closesocket(). However, this appears to be being blocked by the call to recv() in the receive thread.


  2. The main application is unable to transmit data while the receive thread has a call to recv() in progress.



The socket is being created via the accept() function. At this stage I’m not setting any socket options.



I've now created a simple two thread program which illustrates the problem. Without the WSA_FLAG_OVERLAPPED flag, the second thread gets blocked by the first thread, even though this would appear to be contrary to what is supposed to happen. If the WSA_FLAG_OVERLAPPED flag is set, then everything works as I would expect.



PROJECT SOURCE FILE:
====================

program Blocking;

uses
Forms,
Blocking_Test in 'Blocking_Test.pas' {Form1},
Close_Test in 'Close_Test.pas';

{$R *.res}

begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end. { Blocking }

UNIT 1 SOURCE FILE:
===================

unit Blocking_Test;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, WinSock2;

type
TForm1 = class(TForm)
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
Test_Socket: TSocket;
Test_Addr: TSockAddr;
wsda: TWSADATA; { used to store info returned from WSAStartup }

implementation

{$R *.dfm}

uses
Debugger, Close_Test;

procedure TForm1.FormShow(Sender: TObject);
const
Test_Port: word = 3804;
var
Buffer: array [0..127] of byte;
Bytes_Read: integer;
begin { TForm1.FormShow }
Debug('Main thread started');
assert(WSAStartup(MAKEWORD(2,2), wsda) = 0); { WinSock load version 2.2 }
Test_Socket := WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, nil, 0, 0{WSA_FLAG_OVERLAPPED});
assert(Test_Socket <> INVALID_SOCKET);
with Test_Addr do
begin
sin_family := AF_INET;
sin_port := htons(Test_Port);
sin_addr.s_addr := 0; { this will be filled in by bind }
end; { with This_PC_Address }
assert(bind(Test_Socket, @Test_Addr, SizeOf(Test_Addr)) = 0);
Close_Thread := TClose_Thread.Create(false); { start thread immediately }
Debug('B4 Rx');
Bytes_Read := recv(Test_Socket, Buffer, SizeOf(Buffer), 0);
Debug('After Rx');
end; { TForm1.FormShow }

end. { Blocking_Test }

UNIT 2 SOURCE FILE:
===================

unit Close_Test;

interface

uses
Classes;

type
TClose_Thread = class(TThread)
protected
procedure Execute; override;
end; { TClose_Thread }

var
Close_Thread: TClose_Thread;

implementation

uses
Blocking_Test, Debugger, Windows, WinSock2;

type
TThreadNameInfo = record
FType: LongWord; // must be 0x1000
FName: PChar; // pointer to name (in user address space)
FThreadID: LongWord; // thread ID (-1 indicates caller thread)
FFlags: LongWord; // reserved for future use, must be zero
end; { TThreadNameInfo }

var
ThreadNameInfo: TThreadNameInfo;

procedure TClose_Thread.Execute;

procedure SetName;
begin { SetName }
ThreadNameInfo.FType := $1000;
ThreadNameInfo.FName := 'Ping_Thread';
ThreadNameInfo.FThreadID := $FFFFFFFF;
ThreadNameInfo.FFlags := 0;
try
RaiseException( $406D1388, 0, sizeof(ThreadNameInfo) div sizeof(LongWord), @ThreadNameInfo );
except
end; { try }
end; { SetName }

begin { TClose_Thread.Execute }
Debug('Close thread started');
SetName;
sleep(10000); { wait 10 seconds }
Debug('B4 Close');
closesocket(Test_Socket);
Debug('After Close');
end; { TClose_Thread.Execute }

end. { Close_Test }


P.S. Since setting the WSA_FLAG_OVERLAPPED attribute has fixed the problem, I've posted the above for academic interest.










share|improve this question
















I’m writing a simple Windows TCP/IP server application, which only needs to communicate with one client at a time. My application has four threads:




  1. Main program which also handles transmission of data as needed.

  2. Receive incoming data thread.

  3. Listen thread to accept connection requests from the client.

  4. A ping thread which monitors everything else, and transmits heartbeat messages as needed. I realise that the latter shouldn’t really be necessary with TCP/IP, but the client application (over which I have no control) requires this.


I’ve confirmed in task manager that my application does indeed have four threads running.



I’m using blocking TCP/IP sockets, but my understanding is that they only block the calling thread – the other threads should still be allowed to execute without being blocked. However, I have encountered the following issues:




  1. If the ping thread deems the connection to have died, it calls closesocket(). However, this appears to be being blocked by the call to recv() in the receive thread.


  2. The main application is unable to transmit data while the receive thread has a call to recv() in progress.



The socket is being created via the accept() function. At this stage I’m not setting any socket options.



I've now created a simple two thread program which illustrates the problem. Without the WSA_FLAG_OVERLAPPED flag, the second thread gets blocked by the first thread, even though this would appear to be contrary to what is supposed to happen. If the WSA_FLAG_OVERLAPPED flag is set, then everything works as I would expect.



PROJECT SOURCE FILE:
====================

program Blocking;

uses
Forms,
Blocking_Test in 'Blocking_Test.pas' {Form1},
Close_Test in 'Close_Test.pas';

{$R *.res}

begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end. { Blocking }

UNIT 1 SOURCE FILE:
===================

unit Blocking_Test;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, WinSock2;

type
TForm1 = class(TForm)
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
Test_Socket: TSocket;
Test_Addr: TSockAddr;
wsda: TWSADATA; { used to store info returned from WSAStartup }

implementation

{$R *.dfm}

uses
Debugger, Close_Test;

procedure TForm1.FormShow(Sender: TObject);
const
Test_Port: word = 3804;
var
Buffer: array [0..127] of byte;
Bytes_Read: integer;
begin { TForm1.FormShow }
Debug('Main thread started');
assert(WSAStartup(MAKEWORD(2,2), wsda) = 0); { WinSock load version 2.2 }
Test_Socket := WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, nil, 0, 0{WSA_FLAG_OVERLAPPED});
assert(Test_Socket <> INVALID_SOCKET);
with Test_Addr do
begin
sin_family := AF_INET;
sin_port := htons(Test_Port);
sin_addr.s_addr := 0; { this will be filled in by bind }
end; { with This_PC_Address }
assert(bind(Test_Socket, @Test_Addr, SizeOf(Test_Addr)) = 0);
Close_Thread := TClose_Thread.Create(false); { start thread immediately }
Debug('B4 Rx');
Bytes_Read := recv(Test_Socket, Buffer, SizeOf(Buffer), 0);
Debug('After Rx');
end; { TForm1.FormShow }

end. { Blocking_Test }

UNIT 2 SOURCE FILE:
===================

unit Close_Test;

interface

uses
Classes;

type
TClose_Thread = class(TThread)
protected
procedure Execute; override;
end; { TClose_Thread }

var
Close_Thread: TClose_Thread;

implementation

uses
Blocking_Test, Debugger, Windows, WinSock2;

type
TThreadNameInfo = record
FType: LongWord; // must be 0x1000
FName: PChar; // pointer to name (in user address space)
FThreadID: LongWord; // thread ID (-1 indicates caller thread)
FFlags: LongWord; // reserved for future use, must be zero
end; { TThreadNameInfo }

var
ThreadNameInfo: TThreadNameInfo;

procedure TClose_Thread.Execute;

procedure SetName;
begin { SetName }
ThreadNameInfo.FType := $1000;
ThreadNameInfo.FName := 'Ping_Thread';
ThreadNameInfo.FThreadID := $FFFFFFFF;
ThreadNameInfo.FFlags := 0;
try
RaiseException( $406D1388, 0, sizeof(ThreadNameInfo) div sizeof(LongWord), @ThreadNameInfo );
except
end; { try }
end; { SetName }

begin { TClose_Thread.Execute }
Debug('Close thread started');
SetName;
sleep(10000); { wait 10 seconds }
Debug('B4 Close');
closesocket(Test_Socket);
Debug('After Close');
end; { TClose_Thread.Execute }

end. { Close_Test }


P.S. Since setting the WSA_FLAG_OVERLAPPED attribute has fixed the problem, I've posted the above for academic interest.







multithreading delphi winsock






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 4 at 4:54







Chris Hubbard

















asked Jan 2 at 7:25









Chris HubbardChris Hubbard

104




104













  • Can you please put the source code? recv should block only a thread where it resides. Otherwise, one connected client could block another client in a separate thread by issuing slow requests/responses.

    – karastojko
    Jan 2 at 7:38











  • OK, but it'll take a little while for me to make something small enough which just contains the relevant sections.

    – Chris Hubbard
    Jan 2 at 8:09











  • I’m still working on creating a small enough test program to list here, but in the meantime another thought has occurred to me: Can threads “own” other threads, and in so doing cause one thread to block another? My application is written in Delphi, and I’m using it’s standard TThread component.

    – Chris Hubbard
    Jan 2 at 10:13











  • @MartynA on Windows, closing a socket indeed cancels blocking operations in progress in other threads.

    – Remy Lebeau
    Jan 2 at 17:25











  • @ChrisHubbard are you, by chance, using your own critical section or mutex around blocking socket operations? Without seeing your actual code, that is the only way I can think of for this to happen. By themselves, blocking sockets do not behave the way you have described.

    – Remy Lebeau
    Jan 2 at 17:34





















  • Can you please put the source code? recv should block only a thread where it resides. Otherwise, one connected client could block another client in a separate thread by issuing slow requests/responses.

    – karastojko
    Jan 2 at 7:38











  • OK, but it'll take a little while for me to make something small enough which just contains the relevant sections.

    – Chris Hubbard
    Jan 2 at 8:09











  • I’m still working on creating a small enough test program to list here, but in the meantime another thought has occurred to me: Can threads “own” other threads, and in so doing cause one thread to block another? My application is written in Delphi, and I’m using it’s standard TThread component.

    – Chris Hubbard
    Jan 2 at 10:13











  • @MartynA on Windows, closing a socket indeed cancels blocking operations in progress in other threads.

    – Remy Lebeau
    Jan 2 at 17:25











  • @ChrisHubbard are you, by chance, using your own critical section or mutex around blocking socket operations? Without seeing your actual code, that is the only way I can think of for this to happen. By themselves, blocking sockets do not behave the way you have described.

    – Remy Lebeau
    Jan 2 at 17:34



















Can you please put the source code? recv should block only a thread where it resides. Otherwise, one connected client could block another client in a separate thread by issuing slow requests/responses.

– karastojko
Jan 2 at 7:38





Can you please put the source code? recv should block only a thread where it resides. Otherwise, one connected client could block another client in a separate thread by issuing slow requests/responses.

– karastojko
Jan 2 at 7:38













OK, but it'll take a little while for me to make something small enough which just contains the relevant sections.

– Chris Hubbard
Jan 2 at 8:09





OK, but it'll take a little while for me to make something small enough which just contains the relevant sections.

– Chris Hubbard
Jan 2 at 8:09













I’m still working on creating a small enough test program to list here, but in the meantime another thought has occurred to me: Can threads “own” other threads, and in so doing cause one thread to block another? My application is written in Delphi, and I’m using it’s standard TThread component.

– Chris Hubbard
Jan 2 at 10:13





I’m still working on creating a small enough test program to list here, but in the meantime another thought has occurred to me: Can threads “own” other threads, and in so doing cause one thread to block another? My application is written in Delphi, and I’m using it’s standard TThread component.

– Chris Hubbard
Jan 2 at 10:13













@MartynA on Windows, closing a socket indeed cancels blocking operations in progress in other threads.

– Remy Lebeau
Jan 2 at 17:25





@MartynA on Windows, closing a socket indeed cancels blocking operations in progress in other threads.

– Remy Lebeau
Jan 2 at 17:25













@ChrisHubbard are you, by chance, using your own critical section or mutex around blocking socket operations? Without seeing your actual code, that is the only way I can think of for this to happen. By themselves, blocking sockets do not behave the way you have described.

– Remy Lebeau
Jan 2 at 17:34







@ChrisHubbard are you, by chance, using your own critical section or mutex around blocking socket operations? Without seeing your actual code, that is the only way I can think of for this to happen. By themselves, blocking sockets do not behave the way you have described.

– Remy Lebeau
Jan 2 at 17:34














2 Answers
2






active

oldest

votes


















2















If the ping thread deems the connection to have died, it calls closesocket(). However, this appears to be being blocked by the call to recv() in the receive thread.




That's just a bug in your code. You cannot free a resource in one thread while another thread is, or might be, using it. You will have to arrange some sane way to ensure that you don't create race conditions around access to the socket.



To be clear, there is no way you can know what that kind of code could possibly do. For example, consider:




  1. The thread actually hasn't called recv yet, it's about to call recv but the scheduler hasn't got around to it yet.

  2. The other thread calls closesocket.

  3. A thread that is part of a system library opens a new socket and happens to get the same socket descriptor you just closed.

  4. Your thread now gets to call recv, only it's receiving on the socket the library opened!


It is your responsibility to avoid these kinds of race conditions or your code will behave unpredictably. There's no way you can know what the consequence of performing random operations on random sockets could be. So you must not release a resource in one thread while another thread is, might be, or (worst of all) might be about to be, using it.



Most likely what's actually happening is that Delphi has some kind of internal synchronization that is trying to save you from disaster by blocking the thread that can't safely make forward progress.






share|improve this answer


























  • Thank you for your answer. In the case of the Ping thread, I could eliminate the need for it to close the socket (and therefore eliminate the potential race condition) provided I was able to add a receive timeout to the socket. So far my attempts to do this have been unsuccessful, hence why I have tried to add this function to the Ping thread. This then raises a new question: how does one add a receive timeout to a blocking socket? As per my original post, the socket is being created by the accept() function.

    – Chris Hubbard
    Jan 2 at 11:04






  • 3





    If you have a new question to ask, ask a new question

    – David Heffernan
    Jan 2 at 11:32











  • @ChrisHubbard You could just have the ping thread shut the connection down without closing the socket.

    – David Schwartz
    Jan 2 at 11:35











  • So it’s OK for the Ping thread to call shutdown() but not closesocket()? I was under the impression that closesocket() called shutdown() anyway. BTW, in this situation there is no need for an orderly shutdown. A hard shutdown is fine.

    – Chris Hubbard
    Jan 2 at 12:55






  • 1





    Note that Windows does not use file descriptors for sockets, unlike how some other platforms do. Sockets are true kernel objects, so it is unlikely for a new socket to get the same value as a recently closed socket. It is also why you can't use non-socket descriptors with select(), and why closesocket() is needed instead of `close().

    – Remy Lebeau
    Jan 2 at 17:30





















0














UPDATE: accept() creates the new socket with the same attributes as the socket used for listening. Since I hadn’t set the WSA_FLAG_OVERLAPPED attribute for the listen socket, this attribute wasn’t being set for the new socket, and options like the receive timeout didn’t do anything.



Setting the WSA_FLAG_OVERLAPPED attribute for the listen socket seems to have fixed the problem. Thus I can now use the receive timeout, and the Ping thread no longer needs to close the socket if no data has been received.



Setting the WSA_FLAG_OVERLAPPED attribute for the listen socket also seems to have addressed the blocking other threads issue.






share|improve this answer


























  • note that the WSASocket() documentation states: "By default, a socket created with the WSASocket() function will not have this overlapped attribute set. In contrast, the socket() function creates a socket that supports overlapped I/O operations as the default behavior." So, if you use socket() to create the listening socket, then accept() will inherit the overlapped attribute.

    – Remy Lebeau
    Jan 3 at 3:19











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54002673%2fwinsock-recv-function-blocking-other-threads%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









2















If the ping thread deems the connection to have died, it calls closesocket(). However, this appears to be being blocked by the call to recv() in the receive thread.




That's just a bug in your code. You cannot free a resource in one thread while another thread is, or might be, using it. You will have to arrange some sane way to ensure that you don't create race conditions around access to the socket.



To be clear, there is no way you can know what that kind of code could possibly do. For example, consider:




  1. The thread actually hasn't called recv yet, it's about to call recv but the scheduler hasn't got around to it yet.

  2. The other thread calls closesocket.

  3. A thread that is part of a system library opens a new socket and happens to get the same socket descriptor you just closed.

  4. Your thread now gets to call recv, only it's receiving on the socket the library opened!


It is your responsibility to avoid these kinds of race conditions or your code will behave unpredictably. There's no way you can know what the consequence of performing random operations on random sockets could be. So you must not release a resource in one thread while another thread is, might be, or (worst of all) might be about to be, using it.



Most likely what's actually happening is that Delphi has some kind of internal synchronization that is trying to save you from disaster by blocking the thread that can't safely make forward progress.






share|improve this answer


























  • Thank you for your answer. In the case of the Ping thread, I could eliminate the need for it to close the socket (and therefore eliminate the potential race condition) provided I was able to add a receive timeout to the socket. So far my attempts to do this have been unsuccessful, hence why I have tried to add this function to the Ping thread. This then raises a new question: how does one add a receive timeout to a blocking socket? As per my original post, the socket is being created by the accept() function.

    – Chris Hubbard
    Jan 2 at 11:04






  • 3





    If you have a new question to ask, ask a new question

    – David Heffernan
    Jan 2 at 11:32











  • @ChrisHubbard You could just have the ping thread shut the connection down without closing the socket.

    – David Schwartz
    Jan 2 at 11:35











  • So it’s OK for the Ping thread to call shutdown() but not closesocket()? I was under the impression that closesocket() called shutdown() anyway. BTW, in this situation there is no need for an orderly shutdown. A hard shutdown is fine.

    – Chris Hubbard
    Jan 2 at 12:55






  • 1





    Note that Windows does not use file descriptors for sockets, unlike how some other platforms do. Sockets are true kernel objects, so it is unlikely for a new socket to get the same value as a recently closed socket. It is also why you can't use non-socket descriptors with select(), and why closesocket() is needed instead of `close().

    – Remy Lebeau
    Jan 2 at 17:30


















2















If the ping thread deems the connection to have died, it calls closesocket(). However, this appears to be being blocked by the call to recv() in the receive thread.




That's just a bug in your code. You cannot free a resource in one thread while another thread is, or might be, using it. You will have to arrange some sane way to ensure that you don't create race conditions around access to the socket.



To be clear, there is no way you can know what that kind of code could possibly do. For example, consider:




  1. The thread actually hasn't called recv yet, it's about to call recv but the scheduler hasn't got around to it yet.

  2. The other thread calls closesocket.

  3. A thread that is part of a system library opens a new socket and happens to get the same socket descriptor you just closed.

  4. Your thread now gets to call recv, only it's receiving on the socket the library opened!


It is your responsibility to avoid these kinds of race conditions or your code will behave unpredictably. There's no way you can know what the consequence of performing random operations on random sockets could be. So you must not release a resource in one thread while another thread is, might be, or (worst of all) might be about to be, using it.



Most likely what's actually happening is that Delphi has some kind of internal synchronization that is trying to save you from disaster by blocking the thread that can't safely make forward progress.






share|improve this answer


























  • Thank you for your answer. In the case of the Ping thread, I could eliminate the need for it to close the socket (and therefore eliminate the potential race condition) provided I was able to add a receive timeout to the socket. So far my attempts to do this have been unsuccessful, hence why I have tried to add this function to the Ping thread. This then raises a new question: how does one add a receive timeout to a blocking socket? As per my original post, the socket is being created by the accept() function.

    – Chris Hubbard
    Jan 2 at 11:04






  • 3





    If you have a new question to ask, ask a new question

    – David Heffernan
    Jan 2 at 11:32











  • @ChrisHubbard You could just have the ping thread shut the connection down without closing the socket.

    – David Schwartz
    Jan 2 at 11:35











  • So it’s OK for the Ping thread to call shutdown() but not closesocket()? I was under the impression that closesocket() called shutdown() anyway. BTW, in this situation there is no need for an orderly shutdown. A hard shutdown is fine.

    – Chris Hubbard
    Jan 2 at 12:55






  • 1





    Note that Windows does not use file descriptors for sockets, unlike how some other platforms do. Sockets are true kernel objects, so it is unlikely for a new socket to get the same value as a recently closed socket. It is also why you can't use non-socket descriptors with select(), and why closesocket() is needed instead of `close().

    – Remy Lebeau
    Jan 2 at 17:30
















2












2








2








If the ping thread deems the connection to have died, it calls closesocket(). However, this appears to be being blocked by the call to recv() in the receive thread.




That's just a bug in your code. You cannot free a resource in one thread while another thread is, or might be, using it. You will have to arrange some sane way to ensure that you don't create race conditions around access to the socket.



To be clear, there is no way you can know what that kind of code could possibly do. For example, consider:




  1. The thread actually hasn't called recv yet, it's about to call recv but the scheduler hasn't got around to it yet.

  2. The other thread calls closesocket.

  3. A thread that is part of a system library opens a new socket and happens to get the same socket descriptor you just closed.

  4. Your thread now gets to call recv, only it's receiving on the socket the library opened!


It is your responsibility to avoid these kinds of race conditions or your code will behave unpredictably. There's no way you can know what the consequence of performing random operations on random sockets could be. So you must not release a resource in one thread while another thread is, might be, or (worst of all) might be about to be, using it.



Most likely what's actually happening is that Delphi has some kind of internal synchronization that is trying to save you from disaster by blocking the thread that can't safely make forward progress.






share|improve this answer
















If the ping thread deems the connection to have died, it calls closesocket(). However, this appears to be being blocked by the call to recv() in the receive thread.




That's just a bug in your code. You cannot free a resource in one thread while another thread is, or might be, using it. You will have to arrange some sane way to ensure that you don't create race conditions around access to the socket.



To be clear, there is no way you can know what that kind of code could possibly do. For example, consider:




  1. The thread actually hasn't called recv yet, it's about to call recv but the scheduler hasn't got around to it yet.

  2. The other thread calls closesocket.

  3. A thread that is part of a system library opens a new socket and happens to get the same socket descriptor you just closed.

  4. Your thread now gets to call recv, only it's receiving on the socket the library opened!


It is your responsibility to avoid these kinds of race conditions or your code will behave unpredictably. There's no way you can know what the consequence of performing random operations on random sockets could be. So you must not release a resource in one thread while another thread is, might be, or (worst of all) might be about to be, using it.



Most likely what's actually happening is that Delphi has some kind of internal synchronization that is trying to save you from disaster by blocking the thread that can't safely make forward progress.







share|improve this answer














share|improve this answer



share|improve this answer








edited Jan 2 at 10:31

























answered Jan 2 at 10:17









David SchwartzDavid Schwartz

138k14145230




138k14145230













  • Thank you for your answer. In the case of the Ping thread, I could eliminate the need for it to close the socket (and therefore eliminate the potential race condition) provided I was able to add a receive timeout to the socket. So far my attempts to do this have been unsuccessful, hence why I have tried to add this function to the Ping thread. This then raises a new question: how does one add a receive timeout to a blocking socket? As per my original post, the socket is being created by the accept() function.

    – Chris Hubbard
    Jan 2 at 11:04






  • 3





    If you have a new question to ask, ask a new question

    – David Heffernan
    Jan 2 at 11:32











  • @ChrisHubbard You could just have the ping thread shut the connection down without closing the socket.

    – David Schwartz
    Jan 2 at 11:35











  • So it’s OK for the Ping thread to call shutdown() but not closesocket()? I was under the impression that closesocket() called shutdown() anyway. BTW, in this situation there is no need for an orderly shutdown. A hard shutdown is fine.

    – Chris Hubbard
    Jan 2 at 12:55






  • 1





    Note that Windows does not use file descriptors for sockets, unlike how some other platforms do. Sockets are true kernel objects, so it is unlikely for a new socket to get the same value as a recently closed socket. It is also why you can't use non-socket descriptors with select(), and why closesocket() is needed instead of `close().

    – Remy Lebeau
    Jan 2 at 17:30





















  • Thank you for your answer. In the case of the Ping thread, I could eliminate the need for it to close the socket (and therefore eliminate the potential race condition) provided I was able to add a receive timeout to the socket. So far my attempts to do this have been unsuccessful, hence why I have tried to add this function to the Ping thread. This then raises a new question: how does one add a receive timeout to a blocking socket? As per my original post, the socket is being created by the accept() function.

    – Chris Hubbard
    Jan 2 at 11:04






  • 3





    If you have a new question to ask, ask a new question

    – David Heffernan
    Jan 2 at 11:32











  • @ChrisHubbard You could just have the ping thread shut the connection down without closing the socket.

    – David Schwartz
    Jan 2 at 11:35











  • So it’s OK for the Ping thread to call shutdown() but not closesocket()? I was under the impression that closesocket() called shutdown() anyway. BTW, in this situation there is no need for an orderly shutdown. A hard shutdown is fine.

    – Chris Hubbard
    Jan 2 at 12:55






  • 1





    Note that Windows does not use file descriptors for sockets, unlike how some other platforms do. Sockets are true kernel objects, so it is unlikely for a new socket to get the same value as a recently closed socket. It is also why you can't use non-socket descriptors with select(), and why closesocket() is needed instead of `close().

    – Remy Lebeau
    Jan 2 at 17:30



















Thank you for your answer. In the case of the Ping thread, I could eliminate the need for it to close the socket (and therefore eliminate the potential race condition) provided I was able to add a receive timeout to the socket. So far my attempts to do this have been unsuccessful, hence why I have tried to add this function to the Ping thread. This then raises a new question: how does one add a receive timeout to a blocking socket? As per my original post, the socket is being created by the accept() function.

– Chris Hubbard
Jan 2 at 11:04





Thank you for your answer. In the case of the Ping thread, I could eliminate the need for it to close the socket (and therefore eliminate the potential race condition) provided I was able to add a receive timeout to the socket. So far my attempts to do this have been unsuccessful, hence why I have tried to add this function to the Ping thread. This then raises a new question: how does one add a receive timeout to a blocking socket? As per my original post, the socket is being created by the accept() function.

– Chris Hubbard
Jan 2 at 11:04




3




3





If you have a new question to ask, ask a new question

– David Heffernan
Jan 2 at 11:32





If you have a new question to ask, ask a new question

– David Heffernan
Jan 2 at 11:32













@ChrisHubbard You could just have the ping thread shut the connection down without closing the socket.

– David Schwartz
Jan 2 at 11:35





@ChrisHubbard You could just have the ping thread shut the connection down without closing the socket.

– David Schwartz
Jan 2 at 11:35













So it’s OK for the Ping thread to call shutdown() but not closesocket()? I was under the impression that closesocket() called shutdown() anyway. BTW, in this situation there is no need for an orderly shutdown. A hard shutdown is fine.

– Chris Hubbard
Jan 2 at 12:55





So it’s OK for the Ping thread to call shutdown() but not closesocket()? I was under the impression that closesocket() called shutdown() anyway. BTW, in this situation there is no need for an orderly shutdown. A hard shutdown is fine.

– Chris Hubbard
Jan 2 at 12:55




1




1





Note that Windows does not use file descriptors for sockets, unlike how some other platforms do. Sockets are true kernel objects, so it is unlikely for a new socket to get the same value as a recently closed socket. It is also why you can't use non-socket descriptors with select(), and why closesocket() is needed instead of `close().

– Remy Lebeau
Jan 2 at 17:30







Note that Windows does not use file descriptors for sockets, unlike how some other platforms do. Sockets are true kernel objects, so it is unlikely for a new socket to get the same value as a recently closed socket. It is also why you can't use non-socket descriptors with select(), and why closesocket() is needed instead of `close().

– Remy Lebeau
Jan 2 at 17:30















0














UPDATE: accept() creates the new socket with the same attributes as the socket used for listening. Since I hadn’t set the WSA_FLAG_OVERLAPPED attribute for the listen socket, this attribute wasn’t being set for the new socket, and options like the receive timeout didn’t do anything.



Setting the WSA_FLAG_OVERLAPPED attribute for the listen socket seems to have fixed the problem. Thus I can now use the receive timeout, and the Ping thread no longer needs to close the socket if no data has been received.



Setting the WSA_FLAG_OVERLAPPED attribute for the listen socket also seems to have addressed the blocking other threads issue.






share|improve this answer


























  • note that the WSASocket() documentation states: "By default, a socket created with the WSASocket() function will not have this overlapped attribute set. In contrast, the socket() function creates a socket that supports overlapped I/O operations as the default behavior." So, if you use socket() to create the listening socket, then accept() will inherit the overlapped attribute.

    – Remy Lebeau
    Jan 3 at 3:19
















0














UPDATE: accept() creates the new socket with the same attributes as the socket used for listening. Since I hadn’t set the WSA_FLAG_OVERLAPPED attribute for the listen socket, this attribute wasn’t being set for the new socket, and options like the receive timeout didn’t do anything.



Setting the WSA_FLAG_OVERLAPPED attribute for the listen socket seems to have fixed the problem. Thus I can now use the receive timeout, and the Ping thread no longer needs to close the socket if no data has been received.



Setting the WSA_FLAG_OVERLAPPED attribute for the listen socket also seems to have addressed the blocking other threads issue.






share|improve this answer


























  • note that the WSASocket() documentation states: "By default, a socket created with the WSASocket() function will not have this overlapped attribute set. In contrast, the socket() function creates a socket that supports overlapped I/O operations as the default behavior." So, if you use socket() to create the listening socket, then accept() will inherit the overlapped attribute.

    – Remy Lebeau
    Jan 3 at 3:19














0












0








0







UPDATE: accept() creates the new socket with the same attributes as the socket used for listening. Since I hadn’t set the WSA_FLAG_OVERLAPPED attribute for the listen socket, this attribute wasn’t being set for the new socket, and options like the receive timeout didn’t do anything.



Setting the WSA_FLAG_OVERLAPPED attribute for the listen socket seems to have fixed the problem. Thus I can now use the receive timeout, and the Ping thread no longer needs to close the socket if no data has been received.



Setting the WSA_FLAG_OVERLAPPED attribute for the listen socket also seems to have addressed the blocking other threads issue.






share|improve this answer















UPDATE: accept() creates the new socket with the same attributes as the socket used for listening. Since I hadn’t set the WSA_FLAG_OVERLAPPED attribute for the listen socket, this attribute wasn’t being set for the new socket, and options like the receive timeout didn’t do anything.



Setting the WSA_FLAG_OVERLAPPED attribute for the listen socket seems to have fixed the problem. Thus I can now use the receive timeout, and the Ping thread no longer needs to close the socket if no data has been received.



Setting the WSA_FLAG_OVERLAPPED attribute for the listen socket also seems to have addressed the blocking other threads issue.







share|improve this answer














share|improve this answer



share|improve this answer








edited Jan 3 at 1:32

























answered Jan 3 at 0:59









Chris HubbardChris Hubbard

104




104













  • note that the WSASocket() documentation states: "By default, a socket created with the WSASocket() function will not have this overlapped attribute set. In contrast, the socket() function creates a socket that supports overlapped I/O operations as the default behavior." So, if you use socket() to create the listening socket, then accept() will inherit the overlapped attribute.

    – Remy Lebeau
    Jan 3 at 3:19



















  • note that the WSASocket() documentation states: "By default, a socket created with the WSASocket() function will not have this overlapped attribute set. In contrast, the socket() function creates a socket that supports overlapped I/O operations as the default behavior." So, if you use socket() to create the listening socket, then accept() will inherit the overlapped attribute.

    – Remy Lebeau
    Jan 3 at 3:19

















note that the WSASocket() documentation states: "By default, a socket created with the WSASocket() function will not have this overlapped attribute set. In contrast, the socket() function creates a socket that supports overlapped I/O operations as the default behavior." So, if you use socket() to create the listening socket, then accept() will inherit the overlapped attribute.

– Remy Lebeau
Jan 3 at 3:19





note that the WSASocket() documentation states: "By default, a socket created with the WSASocket() function will not have this overlapped attribute set. In contrast, the socket() function creates a socket that supports overlapped I/O operations as the default behavior." So, if you use socket() to create the listening socket, then accept() will inherit the overlapped attribute.

– Remy Lebeau
Jan 3 at 3:19


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54002673%2fwinsock-recv-function-blocking-other-threads%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

A Topological Invariant for $pi_3(U(n))$