Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

threads::shared - acquire lock on an object that has a socket

by aral (Initiate)
on Apr 25, 2014 at 11:59 UTC ( #1083780=perlquestion: print w/ replies, xml ) Need Help??
aral has asked for the wisdom of the Perl Monks concerning the following question:

Hey everyone!

I am trying to serve multiple TCP connections and encapsulate the server for each connection into a class handling its own socket.

1) The main thread starts a TCP connection server, to accept incoming connections
2) The TCP connection server accepts new connections, creates a new object for each connection, adds the handle to an array of connection objects, and forks the connection handler thread
3) the object connection handler then handles the connection itself

My main application is actually distributing a data stream onto several TCP clients. Therefore, my main thread must serve a send buffer with data to be used by the connection handler threads. For cleaner coding (and due to the low total number of connections), I decided to create a separate send buffer for each connection.

The main thread and the connection handler threads need to acquire a lock on the connection object's send buffer. Therefore I make the objects blessed self-reference shared, and can acquire a lock on the objects reference both from the main thread as well as from within the objects methods (rudimentary object example code below).

Problem: the TCP connection handler gets an open socket from the IO::Socket::INET accept() method. When I try to pass this open socket as an argument to my object constructor, the interpreter complains about an Invalid value for shared scalar in the constructor, because apparently it is not allowed to share a socket variable.

I am somewhat at a loss, because I don't actually want to share the *socket* itself, I simply want to acquire a lock on the buffer variables of my connection object. Is there another way to do this for thread-safe handling of the send buffer per object?

Thanks in advance!

Example for connection class:

{ package IPConnection; use threads; use threads::shared; use Time::HiRes qw(time sleep); sub new { my $class = shift; my $arg = shift; share (my %this); $this{_socket} = shift; $this{_sendBufferCount} = 0; bless \%this, $class; return \%this; } sub handleConnection { my $this = shift; my $someData = "foo"; { # scope for lock on $this lock ($this); push @{$this->{_sendBuffer}}, $someData; # manipulate the + send buffer $this->{_sendBufferCount}++; # manipulate the + send buffer } # release lock } }

Comment on threads::shared - acquire lock on an object that has a socket
Download Code
Re: threads::shared - acquire lock on an object that has a socket
by BrowserUk (Pope) on Apr 25, 2014 at 12:53 UTC

    See notes; answer embedded questions:

    sub new { my $class = shift; my $arg = shift; ## What is $arg? Why is it never used? # share (my %this); ## this is an obfuscated way to share a variabl +e my %this :shared; ## the correct way $this{_socket} = shift; ## Presumably this is the socket? Is this +where you get the error? $this{_sendBufferCount} = 0; ## bless \%this, $class; ## bless returns the blessed reference; yo +u are throwing it away ## return \%this; ## this returns an unblessed reference to the has +h -- no good for OO. ## Do it this way. return bless \%this, $class; }

    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.
Re: threads::shared - acquire lock on an object that has a socket
by aral (Initiate) on Apr 25, 2014 at 14:09 UTC

    Thanks for the feedback. I think I managed to lock a separate private variable of the object and now can use a socket inside the object that is not shared and therefore does not cause a conflict.

    This is a fully working perl sample script:

    #!/usr/bin/perl use strict; use warnings; use threads; use threads::shared; { package Foo; use threads::shared; use constant INDENT => "\t\t\t\t\t\t\t\t"; sub new { my $class = shift; my %this; $this{_socket} = shift; $this{_sendBuffer} = []; # TBD: Why does this not work? # my %this = { # _socket => shift, # _sendBuffer => [], # }; share ($this{_sendBuffer}); # make this a shared variable t +o allow main thread to lock & manipulate this return bless \%this, $class; } sub serve { my $this = shift; { # scope for lock on $Foo->{_sendBuffer} print INDENT . "object thread: 1st lock attempt\n"; lock ($this->{_sendBuffer}); print INDENT . "object thread: 1st lock acquired..."; push $this->{_sendBuffer}, "datagram " . scalar (@{$this-> +{_sendBuffer}}); sleep (1); print " and released!\n"; # pretend to release lock + before going out of scope } # release lock sleep (1); { # scope for lock on $Foo->{_sendBuffer} print INDENT . "object thread: 2nd lock attempt\n"; lock ($this->{_sendBuffer}); print INDENT . "object thread: 2nd lock acquired..."; push $this->{_sendBuffer}, "datagram " . scalar (@{$this-> +{_sendBuffer}}); sleep (1); print " and released!\n"; # pretend to release lock +before going out of scope } # release lock } } my $foo = new Foo(); my $thr1 = threads->create(sub { $foo->serve() }); { # scope for lock on $foo print "main thread: 1st lock attempt\n"; lock ($foo->{_sendBuffer}); print "main thread: 1st lock acquired...\n"; print " foo send buffer size: " . scalar (@{$foo->{_sendBuffer} +}) . "\n"; sleep (1); print "main thread: 1st lock released!\n"; } # release lock sleep (1); { # scope for lock on $foo print "main thread: 2nd lock attempt\n"; lock ($foo->{_sendBuffer}); print "main thread: 2nd lock acquired...\n"; print " foo send buffer size: " . scalar (@{$foo->{_sendBuffer} +}) . "\n"; sleep (1); print "main thread: 2nd lock released!\n"; } # release lock $thr1->join(); # for some reason, this calls the destructor of +foo (if present): so the thread obtained a copy of foo to work with? print "main thread: object thread joined\n\n"; my $index = 0; foreach my $item (@{$foo->{_sendBuffer}}) { # loop through contents + of sendBuffer print "foo->{_sendBuffer[$index]}: $item\n"; # output sendBuf +fer contents $index++; } undef ($foo); # destroy object

    I know, I am not really using a socket here - this sample was designed to find a way to use a "mutex" inside an object without locking the whole object. This is accomplished, and from my larger project I can now use a socket in the object.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1083780]
Approved by marto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (6)
As of 2014-12-28 14:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (182 votes), past polls