Не смотря на то, что сейчас усиленно форсится, что перл как язык нынче безнадёжно устарел и ему пора на свалку истории, это совсем не так. Как и раньше, он легко ив непринуждённой манере умеет работать с текстом. Собственно, для того он и писался.
Итак, у меня появилась задача по написанию плагина-уведомлялки на перле, ибо мне интересно получать на десктопе уведомления и том, что там происходит в IRC. Сказано - сделано.
Написал я всё это процедурно и бесхитростно: приходит уведомление, мы стрипаем форматирование, добываем название канала, кто сказал и скармливаем это всё утилите notify-send. И тут же нарываемся на то, что утилита отрабатывает не моментально, а замирает на секунду-две. Всё бы ничего, но внутри себя HexChat построен по принципу 1-й циклической очереди, в которой регистрируются все происходящие эвенты, начиная с отрисовки интерфейса, событий в меню, обработки ввода пользователя и заканчивая сетевыми событиями и событиями, передаваемыми плагинам. Если какое-то событие начинает тормозить, тормозит вся программа. То есть наш HexChat начинает призадумываться, а это уже некомфортно.
Как это обойти, чтобы душевное волнение улеглось и не было столь острым?
Надо сказать программе, что наш плагин будет выполняться долго и нужно просто каждые n секунд заглядывать и проверять как у нас дела, а когда мы доработаем до конца - прибрать за нами и всё.
Делается это просто: мы спавним тред, в котором в шаредной переменной мы по окончании исполнения действия ставим или снимаем флаг. В основном треде мы просто ставим хук на таймер, и говорим проверять раз в некоторое время, как только мы нарываемся в проверке на изменение состояния флага(шаредной переменной), мы джойним тред, снимаем хук и сваливаем из скрипта. Не очень изящно, зато очень эффективно.
Для наглядности: в основной функции:
$active = 1;
my $t = threads->create(\¬ify, $topic, $text);
while (! defined($t)) {
select(undef, undef, undef, 0.25);
$t = threads->create(\¬ify, $topic, $text);
}
$t->detach;
if ($active == 1) {
hook_timer( 100, \&timeraction);
}
return EAT_NONE;
а сам тред:
sub notify(@) {
my($topic, $text) = @_;
`notify-send -u normal -t 12000 -a hexchat "$topic" -i hexchat "$text"`;
$active = 0;
}
ну и timeraction:
sub timeraction {
if ($active == 0) {
return REMOVE;
} else {
return KEEP;
}
}
Реализовав такие "параллельные" уведомления я наткнулся на интересный баг. Есть такой notification демон, под названием dunst, если в него приезжают сразу, параллельно несколько notification-ов, он перестаёт принимать новые уведомления, просто висит и всё. Зато xfce4-notifyd и notification-daemon работают хорошо, но первый уведомлениями облепливает весь экран, а второй просто прячет бОльшую часть уведомлений по счётчик в трее, что какбэ тоже не айс...
Вот так и живём :(