in reply to Passing sockets between segregated threads

... it fails in multithreaded mode during the fdopen() with a "Bad file descriptor" error.

The likely cause is that you are allowing the original file handle to go out of scope and get garbage collected (closed) before the thread to which you pass the fileno has a chance to dup it.

One way to tackle this is to save a copy of the file handle in a hash indexed by it's fileno within the accept thread and then have a separate queue that the responder threads post the filenos to when they close them. The accept thread then monitors this queue and when a fileno is posted to it, it retrieves it and uses it to delete the relevant key from the socket cache to complete the cleanup.


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
  • Comment on Re: Passing sockets between segregated threads

Replies are listed 'Best First'.
Re^2: Passing sockets between segregated threads
by renodino (Curate) on Oct 20, 2005 at 17:11 UTC
    The filehandle isn't going out of scope. If you look at the code snippet, you'll see that threadA() enqueue()'s the fileno to threadB...and Thread::Queue::Duplex::enqueue() is a blocking operation until threadB respond()s...which it doesn't do until it has dequeue()'d and reconstituted the file handle.

      Sorry. I didn't notice you were using T::Q::Duplex, and assumed T::Q.

      However, I recently had exactly the same symptom, "Bad file descriptor" error, trying to dup IO::Socket::INET handles in peer threads, and I cured it, reliably, by the technique I described.

      I'm not familiar with T::Q:Duplex, but I would suggest looking closely at the timing of your code. A few trace statements with HiRes timestamps or simply push a copy of the file handle returned from the accept onto a package scope array and comment out the close. See if it makes a difference.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
      "Science is about questioning the status quo. Questioning authority".
      The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
        You were right...see my update to the OP.

        I forgot that TQD::enqueue() doesn't block, TQD::enqueue_and_wait() does...which also explains my original issue, which relies on Thread::Apartment (also based on TQD) and was using a simplex method to pass the fileno over to the worker thread (simplex methods use nonblocking enqueue_simplex(), rather than enqueue_and_wait(), for the RPC to the apt. threaded object).