Является ли обертка select () в IO :: Select потокобезопасной? Как обойти? - PullRequest
2 голосов
/ 18 июня 2009

Допустим, у меня есть тема:

sub     new {
        my      $class = shift;
        my      $self = ref $class || $class;

        bless { 'read_set'  => IO::Select->new,
                'write_set' => IO::Select->new,
                'error_set' => IO::Select->new }, $self;
}


sub     start {
        my      $self = shift;

        $self->{'thread'} = threads->create(\&worker_thr, $self);
        $self->{'thread'}->detach;
}

sub     worker_thr {
         my      $self = shift;

         while(1) {
                 my($read_active, $write_active, $error_active) = 
                    IO::Select->select(
                            $self->{'read_set'},
                            $self->{'write_set'},
                            $self->{'error_set'}, 
                            undef
                    );
         }

}       

Поскольку я не предоставил время ожидания для select() и оно блокируется на неопределенный срок до тех пор, пока не будет обнаружена активность на одном из наборов дескрипторов (ну, «дескриптор»), что произойдет, если другой поток изменяет содержимое наборов (например, добавляет новая розетка для опроса)?

Реализован ли он потокобезопасным способом по сравнению с реализацией потоков Perl POSIX?

Если нет, то я полагаю, что могу прикрепить блокирующий вызов select() в блоке с его собственной областью действия и заблокировать наборы или, более аккуратно, все данные пакета. Как лучше всего разбудить select() до возврата из другого потока, чтобы можно было манипулировать содержимым наборов? Специфичный для потока сигнал? Семафор? Предложения приветствуются.

Большое спасибо!

Редактировать: Что ж, специфичный для потока "сигнал" отсутствует. Как объясняется здесь (http://perldoc.perl.org/threads.html): «Соответственно, отправка сигнала в поток не нарушает операцию, над которой в данный момент работает поток: Сигнал будет действовать после завершения текущей операции. Например, если поток застревает в вызове ввода-вывода, отправка ему сигнала не приведет к прерыванию вызова ввода-вывода, так что сигнал немедленно активируется. "

Это все еще заставляет меня задуматься, как мне решить проблему пробуждения select() в потоке, если я хочу, чтобы он блокировался бесконечно, а не возвращался после фиксированного времени ожидания.

1 Ответ

2 голосов
/ 18 июня 2009

По умолчанию потоки perl не разделяют никакие данные, поэтому, если один поток изменяет свои наборы, это не повлияет на другой. Так что да, это потокобезопасный, но он, вероятно, не делает то, что вы хотите.

Если вы действительно хотите активировать другой поток или процесс, который блокирует выборку, простое решение - добавить канал в очередь чтения. Затем вы можете разбудить его, записав байт в этот канал.

...