Безопасна ли параллельная запись в eventfd?

Итак, вы хотите направить вывод cmd1 и в cmd2, и в cmd3, и получить вывод cmd2 и cmd3 в разные переменные?

Тогда кажется, что вам нужно два канала из оболочки, один подключен к выходу cmd2 и один к выходу cmd3, и оболочка использует select()/ poll()для чтения из этих двух каналов.

bashдля этого не подойдет, вам понадобится более продвинутая оболочка, такая как zsh. zshне имеет необработанного интерфейса для pipe(), но если вы работаете в Linux, вы можете использовать тот факт, что /dev/fd/xв обычном канале действует как именованный канал, и использовать подход, аналогичный тому, что использовался в Чтение/запись в тот же файловый дескриптор с перенаправлением оболочки

#! /bin/zsh -

cmd1() seq 20
cmd2() sed 's/1/<&>/g'
cmd3() tr 0-9 A-J

zmodload zsh/zselect
zmodload zsh/system
typeset -A done out
{
  cmd1 > >(cmd2 >&3 3>&-) > >(cmd3 >&5 5>&-) 3>&- 5>&- &
  exec 4< /dev/fd/3 6< /dev/fd/5 3>&- 5>&-
  while ((! (done[4] && done[6]))) && zselect -A ready 4 6; do
    for fd (${(k)ready[(R)*r*]}) {
      sysread -i $fd && out[$fd]+=$REPLY || done[$fd]=1
    }
  done
} 3> >(:) 5> >(:)

printf '%s output: <%s>\n' cmd2 "$out[4]" cmd3 "$out[6]"

0
01.07.2020, 14:06
1 ответ

Если вы посмотрите на исходники ядра (здесь 5.4.48 ), вы сможете найти реализацию функций, которые обрабатывают чтение/запись в файловые дескрипторы eventfd:

// fs/eventfd.c

static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
                            loff_t *ppos)
{
        struct eventfd_ctx *ctx = file->private_data;
       ...
        spin_lock_irq(&ctx->wqh.lock);

static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count,
                             loff_t *ppos)
{
        struct eventfd_ctx *ctx = file->private_data;
       ...
        spin_lock_irq(&ctx->wqh.lock);

Реализация имеет внутреннюю блокировку, что делает ее потокобезопасной.

2
18.03.2021, 23:22

Теги

Похожие вопросы