0

I have multiple blocking TCP clients trying to connect and send data to servers. However each operation should not take more than 500ms because the data is time-dependent. On timeout, it should try again. I have seen the alarm() method, but it only accepts seconds. Is there a good way of doing this?

4

2 回答 2

2

If you have a child process per connection, you could use Time::HiRes's ualarm. Otherwise, I don't see why you'd even be tempted to use alarm. It won't even help with threads (since the signal is sent to the process).

A better approach is to keep a note of when a connection was established, and drop the connection if you receive data from the client beyond the 0.5 seconds that follow. Time::HiRes provides a version of time that returns fractional seconds.

This approach works no matter how you provide parallelism (threads, child processes, select, non-blocking operations). It works for both TCP and UDP. And it's even portable.

If everything is in the same thread and process, you can drop dead connections sooner by scanning all connections for timeouts whenever you get data from any connection.


alarm isn't going to help you with threads.

  1. Calls in threads aren't interrupted if you set the handler before starting threads.

    use strict;
    use warnings;
    use threads;
    
    use Time::HiRes qw( time ualarm );
    
    local $SIG{ALRM} = sub { };
    
    {
       ualarm(2 * 1_000_000);
       my $s = time;
       sleep(5);
       my $e = time;
       print "Slept for ".($e-$s)." seconds\n";
    }
    
    for my $thread_idx (0..1) {
       async {
          ualarm(2 * 1_000_000) if $thread_idx == 0;
          my $s = time;
          sleep(5);
          my $e = time;
          print "Thread $thread_idx slept for ".($e-$s)." seconds\n";
       };
    }
    
    $_->join for threads->list;
    

    outputs

    Slept for 2.00284504890442 seconds
    Thread 0 slept for 5.00048089027405 seconds
    Thread 1 slept for 5.00327205657959 seconds
    
  2. Setting the handler in threads has no affect at all.

    use strict;
    use warnings;
    use threads;
    
    use Time::HiRes qw( time ualarm );
    
    for my $thread_idx (0..1) {
       async {
          local $SIG{ALRM} = sub { };
          ualarm(2 * 1_000_000) if $thread_idx == 0;
          my $s = time;
          sleep(5);
          my $e = time;
          print "Thread $thread_idx slept for ".($e-$s)." seconds\n";
       };
    }
    
    $_->join for threads->list;
    

    outputs

    Alarm clock
    
于 2013-06-11T15:32:42.040 回答
2

Time::HiRes模块为您提供了一个微秒粒度的函数ualarm

于 2013-06-11T15:20:27.313 回答