sockets and threads

Discussion in 'Ruby' started by Dominik Werder, Mar 31, 2006.

  1. Hello,

    I observed that even if every thread in a program creates it's own
    Socket, but all to the same Server, then this is not thread-safe.

    It is the same situation as if every thread shared the same Socket
    without any mutexes. I observed this with TCPSockets, UNIXSockets ans
    UDPSockets.

    I run Kernel 2.6.14.2, ruby 1.8.4 (2005-12-24) [i686-linux]


    The short source code below produces the following output on the server.
    If I enabled the mutex (the 3 lines commented out) it would work better.

    Got: thread[16] says 65
    Got: thread[19] says 68thread[17] says 20
    Got:
    Got: thread[24] says 97
    Got: thread[8] says 64thread[26] says 17thread[13] says 43
    Got:
    Got:
    Got: thread[7] says 84
    Got: thread[0] says 78thread[18] says 37
    Got: thread[27] says 98
    Got:
    Got: thread[18] says 13
    Got: thread[11] says 19
    Got: thread[1] says 91thread[26] says 18
    Got:
    Got: thread[1] says 53
    Got: thread[19] says 42


    # First start the server with:
    # ruby tcpsockets.rb server
    # Then start the client which spawns several threads:
    # ruby tcpsockets.rb


    require 'socket'
    require 'monitor'

    if ARGV[0] == 'server'
    threads = []
    server = TCPServer.new 'localhost', 8889
    putslock = Monitor.new
    while socket = server.accept
    t = Thread.new(socket) do |sock|
    while str = sock.gets
    putslock.synchronize do
    puts "Got: #{str}"
    end
    end
    end
    threads << t
    end
    threads.each do |t| t.join end
    else
    Thread.abort_on_exception = true
    #socketlock = Monitor.new
    threads = []
    30.times do |i|
    t = Thread.new(i) do |ii|
    count = 0
    socket = TCPSocket.new 'localhost', 8889
    puts "Using socket #{socket.object_id}"
    while count < 10
    #socketlock.synchronize do
    socket.puts "thread[#{ii}] says #{Kernel.rand 100}"
    socket.flush
    #end
    sleep Kernel.rand * 0.3
    count += 1
    end
    end
    threads << t
    end
    threads.each do |t| t.join end
    end




    Is this known/intended behavior?

    thanks and a good day!
    Dominik
     
    Dominik Werder, Mar 31, 2006
    #1
    1. Advertising

  2. Re: sockets and threads (solved)

    Hello,

    I found the bug: In the client code the variable "socket" was already
    known to the interpreter, but anyway not in the same scope, so every
    thread overwrote the socket and in the end all used the same connection..

    I didn't know that

    if false
    yo = 123
    else
    puts yo.class.name
    end

    would output "NilClass"..

    bye!
    Dominik
     
    Dominik Werder, Mar 31, 2006
    #2
    1. Advertising

  3. Re: sockets and threads (solved)

    Dominik Werder wrote:
    > Hello,
    >
    > I found the bug: In the client code the variable "socket" was already
    > known to the interpreter, but anyway not in the same scope, so every
    > thread overwrote the socket and in the end all used the same connection..
    >
    > I didn't know that
    >
    > if false
    > yo = 123
    > else
    > puts yo.class.name
    > end
    >
    > would output "NilClass"..


    I'm getting more and more defensive about this kind of bug. I usually
    just do

    Thread.new(...) { |...| some_method(...)}

    and then I can code some_method without worrying about local variable
    sharing.

    Another example is when threads are created in a loop. Even if the
    thread code is very small, local vars with shared binding can be
    devastating:

    a = []
    i = 0
    (0...100).map do
    Thread.new {sleep 0.001; a << i}
    i += 1
    end
    sleep 1
    p a.uniq.size


    Output is unpredictable, 74, 86, etc. (YMMV)

    Obviously, this could be solved by making i local to the block, or
    passing it to Thread.new. Without the sleep 0.001, I don't seem to get
    this behavior (the output is 100), but I wouldn't rely on that: the ruby
    thread scheduler could still reasonably schedule threads so that two or
    more of them saw the same value of i. So it's still best to pass
    arguments to Thread.new.

    --
    vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407
     
    Joel VanderWerf, Mar 31, 2006
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jupiter5F

    Threads and Sockets

    Jupiter5F, Nov 14, 2003, in forum: C++
    Replies:
    4
    Views:
    2,335
    Jupiter5F
    Nov 14, 2003
  2. Julia Goolia

    tkinter, sockets and threads together

    Julia Goolia, Sep 11, 2003, in forum: Python
    Replies:
    4
    Views:
    554
    Steve Holden
    Sep 12, 2003
  3. Gonçalo Rodrigues

    Help needed in problem with Threads and sockets.

    Gonçalo Rodrigues, Dec 29, 2003, in forum: Python
    Replies:
    0
    Views:
    292
    Gonçalo Rodrigues
    Dec 29, 2003
  4. Rod Stephenson
    Replies:
    0
    Views:
    466
    Rod Stephenson
    Jun 22, 2004
  5. Ajay

    threads and sockets

    Ajay, Oct 13, 2004, in forum: Python
    Replies:
    3
    Views:
    311
    Elbert Lev
    Oct 14, 2004
Loading...

Share This Page