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

I am working to converting a UPnP DLNA server perl script that someone else wrote for linux to run under windows. I have spent the last couple of evenings trying to resolve some strange behavior with threads.

I have reduced the problem down to a short script and a short perl module which are listed at the bottom of this post.

The situation develops when a multicast socket, created by the main script by calling a subroutine in a package, is accessed by another subroutine in the same package which is running in a thread. What happens is that all the threads hang and the main script hangs when it goes to create the another thread.

In the example below I have set it up so that when the script is run with a 0 passed to createsock it creates a udp socket in the same thread and subroutine that access it. When run in this mode the script runs as expected printing a number of debug messages and then a message block when the script exists that the script ended with 1 thread running. When the script is run with a 1 passed to createsock the udp socket is created in a separate routine in the package. In this case the script prints "start sub 1" and then "above mysub2" where it hangs.

I expect that the problem has something to do with the Windows thread implementation and accessing the $sock variable in the main body of the script and then in a thread.

I would like to fix it in a way that would run both under linux and windows. As I don't have a lot of experience with threads I am looking to the collective wisdom of the perl monks on the most appropriate way to do this.

Your feedback is very much appreciated. I hope I have provided the right amount of information but if there is something else that is needed please let me know.

digitalhack
Rockville, MD

perl script:
use strict; use threads; use lib ('./'); use TEST::TEST; TEST::TEST::createsock(1); my $t1 = threads->create(\&TEST::TEST::mysub1, 1, "test 1"); select(undef, undef, undef, .25); print "above mysub2\n"; my $t2 = threads->create(\&TEST::TEST::mysub2, 2, "test 2"); print "below mysub2\n"; $t2->join();

perl module:
package TEST::TEST; use strict; use threads; use IO::Socket::Multicast; our $sock = undef; sub createsock { my $create = shift @_; if ($create) { $sock = IO::Socket::Multicast->new(Proto=>'udp',LocalPort=>2200); $sock->mcast_add('226.1.1.2') || die "Couldn't set group: $!\n"; } } sub mysub1 { my ($sub, $msg) = shift @_; print "start sub $sub\n"; #my $key = getc(STDIN); my $data; if ($sock == undef) { $sock = IO::Socket::Multicast->new(Proto=>'udp',LocalPort=>2200); $sock->mcast_add('226.1.1.2') || die "Couldn't set group: $!\n"; } $sock->recv($data,1024); print "end sub $sub\n"; } sub mysub2 { my ($sub, $msg) = shift @_; print "start sub $sub\n"; print "msg from sub $sub: $msg\n"; print "end sub $sub\n"; } 1;

Replies are listed 'Best First'.
Re: Threads and Package differences between Linux and Windows
by BrowserUk (Patriarch) on Oct 14, 2011 at 06:11 UTC

    I don't have a perfect solution, nor even a good answer for you, but I do have some observations & speculations.

    The freeze occurs when attempting to create the second thread.

    If you comment out the recv call in the first thread, the freeze does not occur.

    What the subroutine being started in that second thread, is or does, is irrelevant.

    It never reaches the point of being called, nor even the (C) thread being created.

    This I believe can only mean that the OS is deferring the creation of the new thread until the recv completes.

    This does not happen with normal sockets created by IO::Socket.

    As the socket created by IO::Socket::Multicast *is* an IO::Socket instance, the only real difference is that the it has had

    setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,(void*) &mreq,sizeof(mreq)) + < 0)

    called upon it.

    I suspect that the difference 'tween *nix & Windows lies in the implementation of that socket option. I also suspect that using recv on a blocking socket may be an underlying problem

    This latter suspicion is "confirmed" by the following version of your code that sets the socket non-blocking which allows it to run to completion:

    package T; use strict; use threads; use IO::Socket::Multicast; our $sock = undef; sub createsock { my $create = shift @_; my $noBlock == 1; if ($create) { $sock = IO::Socket::Multicast->new(Proto=>'udp',LocalPort=>220 +0); $sock->mcast_add('226.1.1.2') || die "Couldn't set group: $!\n +"; ioctl( $sock, 0x8004667e, \$noBlock ); } } sub mysub1 { my ($sub, $msg) = shift @_; my $noBlock == 1; print "start sub $sub\n"; #my $key = getc(STDIN); my $data; if ($sock == undef) { $sock = IO::Socket::Multicast->new(Proto=>'udp',LocalPort=>220 +0); $sock->mcast_add('226.1.1.2') || die "Couldn't set group: $!\n +"; ioctl( $sock, 0x8004667e, \$noBlock ); } $sock->recv($data,1024); print "end sub $sub\n"; } sub mysub2 { my ($sub, $msg) = shift @_; print "start sub $sub\n"; print "msg from sub $sub: $msg\n"; print "end sub $sub\n"; } package main; T::createsock(1); my $t1 = threads->create( \&T::mysub1, 1, "test 1"); select(undef, undef, undef, .25); print "above mysub2\n"; my $t2 = threads->create( sub{ warn }, 2, "test 2"); print "below mysub2\n"; $t2->join();

    Whether this can work with your application ...


    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".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Thank you for sharing these observations.
A reply falls below the community's threshold of quality. You may see it by logging in.