José,

Thanks for the info, but forget that I'm using pipes. I need that the perl
script, when is executed, first detect if it is already executing and if it
is wait for some miliseconds. I'm new in Perl so I don't know how to get
this, but if this was possible I think that it would solve my problem.

Regards,

Enric


----- Mensaje original -----
De: "NYIMI Jose (BMB)" <[EMAIL PROTECTED]>
Para: "Enric Roca" <[EMAIL PROTECTED]>; "Beginners Perl"
<[EMAIL PROTECTED]>
Enviado: lunes 27 de enero de 2003 15:09
Asunto: RE: Concurrency problem


Sorry :) but your script seems not doing what you explained above.
I have the impression that your problem is not related to a concurrency
problem.
Could you send a more detailed code, please?

José.

Anyway, here some reads from Perl Cookbook :


16.11. Making a Process Look Like a File with Named Pipes
Problem
You want a process to intercept all access to a file. For instance, you want
to make your ~/.plan file a program that returns a random quote.

Solution
Use named pipes. First create one, probably from your shell:

% mkfifo /path/to/named.pipe
Here's a reader for it:

open(FIFO, "< /path/to/named.pipe")         or die $!;
while (<FIFO>) {
    print "Got: $_";
}
close(FIFO);
Here's a writer for it:

open(FIFO, "> /path/to/named.pipe")         or die $!;
print FIFO "Smoke this.\n";
close(FIFO);
Discussion
A named pipe, or FIFO as they are also known, is a special file that acts as
a buffer to connect processes on the same machine. Ordinary pipes also allow
processes to communicate, but those processes must have inherited the
filehandles from their parents. To use a named pipe, a process need know
only the named pipe's filename. In most cases, processes don't even need to
be aware that they're reading from a FIFO.

Named pipes can be read from and written to just as though they were
ordinary files (unlike Unix-domain sockets as discussed in Chapter 17,
Sockets). Data written into the FIFO is buffered up by the operating system,
then read back in the order it was written in. Because a FIFO acts as a
buffer to connect processes, opening one for reading will block until
another process opens it for writing, and vice versa. If you open for read
and write using the +< mode to open, you won't block (on most systems)
because your process could be both reader and writer.

Let's examine how to use a named pipe so people will get a different file
each time they finger you. To create a named pipe, use mkfifo or mknod to
create a named pipe called .plan in your home directory:

% mkfifo ~/.plan                    # isn't this everywhere yet?
% mknod  ~/.plan p                  # in case you don't have mkfifo
On some systems, you must use mknod (8). The location and names of these
programs aren't uniform or necessarily obvious, so consult your system
documentation to find out where these programs are.

The next step is to create a program to feed data to the programs that read
from your ~/.plan file. We'll just print the date and time, as shown in
Example 16.9.

Example 16.9: dateplan
#!/usr/bin/perl -w
# dateplan - place current date and time in .plan file
while (1) {
    open(FIFO, "> $ENV{HOME}/.plan")
        or die "Couldn't open $ENV{HOME}/.plan for writing: $!\n";
    print FIFO "The current time is ", scalar(localtime), "\n";
    close FIFO;
    sleep 1;
}
Unfortunately, this won't always work, because some finger programs and
their attendant daemons check the size of the .plan file before trying to
read it. Because named pipes appear as special files of zero size on the
filesystem, such clients and servers will not try to open or read from our
named pipe, and the trick will fail.

In our .plan example, the writer was a daemon. It's not uncommon for readers
to be daemons as well. Take, for instance, the use of a named pipe to
centralize logging from many processes. The log server reads log messages
from the named pipe and can send them to a database or file. Clients write
their messages to the named pipe. This removes the distribution logic from
the clients, making changes to message distribution easy to implement.

Example 16.10 is a simple program to read two-line messages where the first
line is the name of the service and the second line is the message being
logged. All messages from httpd are ignored, while all messages from login
are saved to /var/log/login.

Example 16.10: fifolog
#!/usr/bin/perl -w
# fifolog - read and record log msgs from fifo

use IO::File;

$SIG{ALRM} = sub { close(FIFO) };   # move on to the next queued process

while (1) {
    alarm(0);                       # turn off alarm for blocking open
    open(FIFO, "< /tmp/log")        or die "Can't open /tmp/log : $!\n";
    alarm(1);                       # you have 1 second to log

    $service = <FIFO>;
    next unless defined $service;   # interrupted or nothing logged
    chomp $service;

    $message = <FIFO>;
    next unless defined $message;   # interrupted or nothing logged
    chomp $message;

    alarm(0);                       # turn off alarms for message processing

    if ($service eq "http") {
        # ignoring
    } elsif ($service eq "login") {
        # log to /var/log/login
        if ( open(LOG, ">> /tmp/login") ) {
            print LOG scalar(localtime), " $service $message\n";
            close(LOG);
        } else {
            warn "Couldn't log $service $message to /var/log/login : $!\n";
        }
    }
}
This program is more complicated than the .plan program for several reasons.
First and foremost, we don't want our logging server to block would-be
writers for long. It's easy to imagine a situation where an attacker or
misbehaving writer opens the named pipe for writing, but doesn't send a
complete message. To prevent this, we use alarm and SIGALRM to signal us if
we get stuck reading.

Only two exceptional conditions can happen when using named pipes: a writer
can have its reader disappear, or vice versa. If a process is reading from a
named pipe and the writer closes its end, the reading process will get an
end of file (<> returns undef). If the reader closes the connection, though,
the writer will get a SIGPIPE when it next tries to write there. If you
disregard broken pipe signals with $SIG{PIPE} = 'IGNORE', your print will
return a false value and $! will be set to EPIPE:

use POSIX qw(:errno_h);

$SIG{PIPE} = 'IGNORE';
# ...
$status = print FIFO "Are you there?\n";
if (!$status && $! == EPIPE) {
    warn "My reader has forsaken me!\n";
    next;
}
You may be asking "If I have 100 processes all trying simultaneously to
write to this server, how can I be sure that I'll get 100 separate entries
and not a jumbled mishmash with characters or lines from different
processes?" That's a good question. The POSIX standard says that writes of
less than PIPE_BUF bytes in size will be delivered atomically, i.e. not
jumbled. You can get the PIPE_BUF constant from POSIX:

use POSIX;
print _POSIX_PIPE_BUF, "\n";
Fortunately, the POSIX standard also requires PIPE_BUF to be at least 512
bytes. This means that all we have to do is ensure that our clients don't
try to log more than 512 bytes at a time.

What if you want to log more than 512 bytes at a time? Then you split each
large message into several smaller (fewer than 512 bytes) messages, preface
each with the unique client identifier (process ID, say) and have the server
reassemble them. This is similar to the processing involved in TCP/IP
message fragmentation and reassembly.

Because a single named pipe doesn't allow bidirectional access between
writer and reader, authentication and similar ways of preventing forged
messages are hard to do (if not impossible). Rather than struggle to force
such things on top of a model that doesn't accommodate them, you are better
off using the filesystem's access control to restrict access to the file
through the owner and group permissions on the named pipe.

See Also
mkfifo (8) or mknod (8) (if you have them); Recipe 17.6


> -----Original Message-----
> From: Enric Roca [mailto:[EMAIL PROTECTED]]
> Sent: Monday, January 27, 2003 12:21 PM
> To: Beginners Perl
> Subject: Concurrency problem
>
>
> Hello,
>
> We are using Apache 1.3.26, Perl 5.5.3 and  perl-cgi
> scripting to communicate to applications with XML. App1 calls
> the cgi script that is placed in the other machine. The
> script reads the XML message and pass it to pipe1. This
> message is processed by App2 and a response message is
> returned to pipe2 and sent to App1.
>
> The process works fine, but we have detected an issue when
> more that one XML message is sent at the same time. The first
> message that arrives is well processed but the second message is lost.
>
> Any ideas about what to do in the Perl script to avoid
> concurrency problems ?
>
> This is the script:
>
>
> #!/usr/local/bin/perl
> print "Content-type: text/xml\n";
> use CGI;
> read(STDIN, $cadena, $ENV{'CONTENT_LENGTH'});
>
> $cadena =~ tr/+/ /;     # reeplace the + sign by spaces
>
> $request = "> /myfolder/mypipe/pipe1";
>
> unless (open(SYSREQUEST, $request))
>   {
>     die("Impossible to open the pipe $request\n");
>   }
>
> print SYSREQUEST "$cadena\n";
>
> close(SYSREQUEST);
>
> $request2 = "/myfolder/mypipe/pipe2";
>
> unless (open(SYSREQUEST2, $request2))
>   {
>     die("Impossible to open the pipe $request2\n");
>   }
>
> while ( <SYSREQUEST2> )
> {
>   print "$_\n";
> }
> close(SYSREQUEST2);
>
>
> Thank you very much in advance,
>
> Enric
>
>
>
> --
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
>
>


**** DISCLAIMER ****

"This e-mail and any attachment thereto may contain information which is
confidential and/or protected by intellectual property rights and are
intended for the sole use of the recipient(s) named above.
Any use of the information contained herein (including, but not limited to,
total or partial reproduction, communication or distribution in any form) by
other persons than the designated recipient(s) is prohibited.
If you have received this e-mail in error, please notify the sender either
by telephone or by e-mail and delete the material from any computer".

Thank you for your cooperation.

For further information about Proximus mobile phone services please see our
website at http://www.proximus.be or refer to any Proximus agent.



-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to