Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I am considering writing a multi-threaded application with the following (over simplified) design:

I know how to share a socket between threads but I wonder if two threads can interact safely with the same IO::Socket object.

Googling around, it seems that IO::Socket objects are thread safe but the word "thread" does not even appear in the official documentation (IO::Socket or IO::Socket::INET).

So, can two threads safely interact with the same IO::Socket object?

Is this also true also for IO::Socket::SSL sockets (assuming a recent version of Net::SSLeay)?

  • Comment on Can I/O operations on the same IO::Socket be executed in different threads?

Replies are listed 'Best First'.
Re: Can I/O operations on the same IO::Socket be executed in different threads?
by BrowserUk (Patriarch) on May 12, 2015 at 05:51 UTC
    So, can two threads safely interact with the same IO::Socket object?

    No. (For earlier discussion see:Keeping an INET socket inside a shared object)


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
    In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
Re: Can I/O operations on the same IO::Socket be executed in different threads?
by ikegami (Patriarch) on May 12, 2015 at 15:12 UTC

    If the only thing you do with the IO::Socket::INET and read and write from it, you won't have any problem since the object is not used at all for that (just the file handle on which its built).

    use strict; use warnings; use threads; use IO::Socket::INET qw( ); use constant SHUT_WR => 1; my $sock = IO::Socket::INET->new( Proto => 'tcp', PeerAddr => $ARGV[0] // 'localhost:echo', ) or die $!; async { print while <$sock>; }; async { print($sock "abc\n"); sleep(3); print($sock "def\n"); shutdown($sock, SHUT_WR); }; $_->join for threads->list;

    I don't know for IO::Socket::SSL.


    Update: Added default argument.

      How laughably naive of you to produce code that does nothing useful and announce: "you won't have any problem".

      No wonder p5p decided to "discourage" threads when "experts" go around handing out advice like that!


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
      In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
        Threads aren't discouraged by p5p. The docs mispeak. It's meant to be a warning on the heavyness of Perl threads. It's already in the process of being fixed.

      That junk dies with  Invalid argument at - line 2

      Or if you go and fix it and specify  'localhost:6666' it dies with No connection could be made because the target machine actively refused it.

      Windows doesn't have Unix domain socket, if thats what your program is supposed to use

      Very poor showing for such a super hyper pedant

        Sounds like you didn't actually run a server at localhost:6666? A simple echo server would do. (You can find one at localhost:echo sometimes, though it's trivial to write one.)


        IO::Socket::INET->new creates a TCP socket, not a unix socket.

      I, too, don’t think that I fully understand the basis from which you speak, and I candidly suspect that your example might produce a “false positive” since it waits three seconds.   Thus, it is probably not a representative example of what might go wrong, since in your example it is unlikely that the threads would ever the threads would never actually conflict with one another.

      When you’re dealing with a real-world remote system, the status of that system is only represented by the single stream of messages that the system is sending-out on each of its sockets.   I think that, therefore, you need to have one thread on your end which is responsible for knowing the status of every one of them.   And, because socket-operations are not terribly fast, a select() loop works perfectly.   One thread, processing “one message at a time” from all sources at once, can always keep up and will never present a bottleneck.

      This venerable strategy elegantly avoids all timing problems.   One thread can easily accommodate all of the connections, and can (centrally) keep track of the status of all of them, so that all of the clients get exactly what they need and want:   “Please send this message to somebody, and give me the reply as soon as you get it.”   Due to the realities of network-I/O (and, remote systems ...), there’s no reason to make things any more complicated, and, as it were, plenty of reasons not to.

        I, too, don’t think that I fully understand the basis from which you speak,

        I figured I'd actually answer the OP's question. You see, the OP asked if one thread could read from a socket while another writes to the same socket.

        BrowserUk's incredible hostility is completely unwarranted. There are common applications for what the OP asks. Tunnels, for one. Another would be to avoid using select+ioctl to do non-blocking output (which probably doesn't work on Windows). I think IPC::Run does exactly this in some circumstances.

Re: Can I/O operations on the same IO::Socket be executed in different threads?
by noxxi (Pilgrim) on May 12, 2015 at 20:20 UTC
    Is this also true also for IO::Socket::SSL sockets (assuming a recent version of Net::SSLeay)?
    As long as these actions are locked against each other and thus do not happen at the same time it should be safe enough. Without locking: no. It is better to restrict yourself so that all actions on the same socket are done in the same thread.

      Just to clarify—you are saying that the concerns in IO::Socket::SSL + fork problem do not apply in this case?

      How do you envision such socket being managed? Perusing threads::shared and my $sock :shared; will ensure coherent state? The Net::SSLeay itself is thread-safe, but does it support shared sockets? Any special concerns, such as nonblocking mode or cross-thread callbacks?

        Once the SSL socket is established all the necessary state for reading and writing is fully managed by the OpenSSL library. That is the Perl socket can be used between multiple threads, but only one thread should use the socket at one time (i.e. needs locking). Forking is different because in this case the SSL state gets duplicated and client and server try to manage their own state independently which will not work because then none of these will reflect the real state of the SSL connection.

        Of course all this means that the Socket must be created before the threads are created. Creating a socket in one thread and then using it in another will not work since the Perl handle can not be shared.

      And yet, one thought that keeps banging against my head is this:   “even if we can ‘make it to work,” does it ‘make sense?’”   That, to me, is actually a key question here:   “does it actually ‘make sense’ that one thread should ‘only read,’ and that another thread, ‘only write?’”   I don’t think so.   Why?   Because somebody needs to be aware of:   “the present-state of the remote client.”   And, furthermore, this “present-state” can only be ascertained, subject to an unforeseen (and, unforeseeable ...) lag.

      Therefore, I suggest that the only truly-practicable design must be this:   “put your letter in the box, raise the flag, and then wait for the postman.”   “The Postman” has no race-conditions within himself.   Therefore, he is able to efficiently serve the needs of any number of clients without conflict.

      To my way of thinking, both of the client-processes in question should be reading/writing from queues that are served by the Postman.   They should not be attempting to read/write from the socket directly.

Re: Can I/O operations on the same IO::Socket be executed in different threads?
by Anonymous Monk on May 12, 2015 at 06:44 UTC

    Threads may share a socket or file descriptor all right, but you probably ought to use low-level Socket module if that is your intent. Any issues with the resource sharing (synchronization, locking, state logic, teardown, and so on) are solely your responsibility. This precludes the use of protocol layers such as SSL.

      Threads may share a socket or file descriptor all right

      Care to back that assertion up with some code that does it; and does something useful?


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
      In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

        I can't speak for the AM, but several years ago I wrote some C code on Linux that shared a socket between 2 threads, one reading, one writing (like what the OP wants to do). It worked for me. I don't know if this would work on MS Windows.

        Any threaded code that spits debugging info (say), ought to satisfy your stipulation. (Although technically, a pty is not a socket. But then again, one might redirect the output.)

Re: Can I/O operations on the same IO::Socket be executed in different threads?
by Anonymous Monk on May 13, 2015 at 02:35 UTC

    This should be portable (works on window ) .... dunno if its better or worse than using Thread::Queue for ipc( qin/qout)

    #!/usr/bin/perl -- use strict; use warnings; use threads stack_size => 4096; use IO::Socket::INET; our $host = "localhost:".int(rand 99999); async( sub { my $tid = threads->tid; use Time::HiRes qw/ usleep /; my $server = IO::Socket::INET->new( Proto => "tcp", LocalHost => $host, Listen => 1, Reuse => 1, ) or die "Cannot start tcp server: $!\n $@\n "; print "listening on $host\n"; sleep 1; my $client = $server->accept(); while(<$client>){ print "reader($tid) $_"; last if /exit/i; } }); async( sub { my $tid = threads->tid; use Time::HiRes qw/ usleep /; my $socket = IO::Socket::INET->new( Proto => "tcp", PeerHost => $host, ) or die "Cannot start client : $!\n $@\n "; for(1..20){ usleep 2000*rand(500); # 2000 sleep for 2 millisecond $socket->print( "writer($tid) ".scalar(gmtime)."\n" ); } $socket->print( "writer($tid) ".scalar(gmtime)." exit\n" ); }); $_->join for threads->list; __END__

      And? You've got two connected endpoints, two descriptors. There's no shared socket.

        And? You've got two connected endpoints, two descriptors. There's no shared socket.

        Yes, that is the point of this example -- it does seem to miss the point of the OP, so yeah :)

Re: Can I/O operations on the same IO::Socket be executed in different threads?
by locked_user sundialsvc4 (Abbot) on May 12, 2015 at 12:08 UTC

    Excellent thread you refer-to ... everyone should read it carefully all the way through.   (I just tossed-out a bunch of up-votes.)

    There is one classic design for working with multiple sockets: a select-loop, which polls a list of sockets to find out which one(s) have data, managed by one thread, which acts as the incoming and outgoing gatekeeper for the entire system.   This design works extremely well, and there are plenty of CPAN modules out there which already implement all of it.

    Network I/O is a comparatively slow operation, so there is plenty of time, even with many sockets to tend.   But there’s also one other important consideration:   the need to track the state of the external systems with which you are communicating.   If a single thread is pulling off a sequential stream of messages from multiple sockets, there will never be any timing issues.   That one thread, with simple FSM = Finite-State Machine logic, can keep track of them all, and can do whatever protocol exchanges are needed.   Meanwhile, the worker threads, who are listening and writing to thread-safe queues populated by the gatekeeper, need have no such concerns.

      Excellent thread you refer-to ... just tossed-out a bunch of up-votes
      You are responding to the root node. The root node does not refer to any PM thread. Nothing to up-vote.

      Once again you are replying to the wrong post. Did you mean to reply to BrowserUk's response?

        Yes, I did up-vote (yes, I said up...) BrowserUK’s comments to this thread and to the other thread that he referred-to ... while also (intending to be) speaking very favorably of it.   I also up-voted several other comments including later ones in the that same thread (near the end of it).

      Don't you ever tire of making a fool of yourself? More of your trade mark utter garbage!


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
      In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
Re: Can I/O operations on the same IO::Socket be executed in different threads?
by Anonymous Monk on May 14, 2015 at 00:56 UTC
    #!/usr/bin/perl -- use strict; use warnings; use threads stack_size => 4096; use IO::Socket::INET; use Time::HiRes qw/ usleep /; use Data::Dump qw/ dd /; Main( @ARGV ); exit( 0 ); sub Main { my $host = "localhost:" . int( rand 99999 ); Dodo( $host, 'IO::Socket::INET' ); ## "works" ## Dodo( $host, 'IO::Socket::SSL' ); use IO::Socket::SSL; ## "doesn +'t" } ## end sub Main sub Dodo { my( $host, $socktype ) = @_; async( \&Server, $host, $socktype ); sleep 1; my $socket = $socktype->new( Proto => "tcp", PeerHost => $host, ) or die "Cannot start client : $!\n $@\n "; $socket->blocking( 0 ); async( \&Reader, $socket ); async( \&Writer, $socket ); $_->join for threads->list; } ## end sub Dodo sub Server { my( $host, $socktype ) = @_; my $tid = threads->tid; use Time::HiRes qw/ usleep /; my $server = $socktype->new( Proto => "tcp", LocalHost => $host, Listen => 1, Reuse => 1, ) or die "Cannot start tcp server: $!\n $@\n "; dd "listening on $host\n"; sleep 1; my $client = $server->accept(); while( <$client> ) { dd "echo reader($tid) $_"; print $client "echo reader($tid) $_"; last if /exit/i; } ## end while( <$client> ) } ## end sub Server sub Writer { my( $socket ) = @_; my $tid = threads->tid; for( 1 .. 20 ) { usleep 2000 * rand( 500 ); # 2000 sleep for 2 millisecond $socket->print( "writer($tid) " . scalar( gmtime ) . "\n" ); } ## end for( 1 .. 20 ) $socket->shutdown( 1 ); ## done writing } ## end sub Writer sub Reader { my( $socket ) = @_; my $tid = threads->tid; my $read = 0; while( $read < 1000 ) { my $readed = $socket->sysread( my $line, 51 ); next if !$readed; $read += $readed; dd "holymolyreaded($read/$readed) $line"; usleep 2000 * rand( 500 ); } ## end while( $read < 1000 ) $socket->print( "reader($tid) " . scalar( gmtime ) . " exit\n" ); } ## end sub Reader __END__
Re: Can I/O operations on the same IO::Socket be executed in different threads?
by ikegami (Patriarch) on May 14, 2015 at 18:02 UTC
    If you're trying to communicate between the two threads using that socket, see this simple solution.