Быстрый производитель/медленный потребитель в C

Я написал программу на C, которая ждет события, а затем запустите внешнюю системную команду с помощью функции system().

while( true ){
    wait_for_event();
    system("cmd");
}

У меня есть проблема с seriuos, The cmd является тяжелой командой и занимает несколько секунд, и мое приложение пропускает некоторые события за этот период времени.

Поэтому я решил переместить функцию system, которая очень тяжелая, в другую программу, поэтому я изменил свою программу следующим образом:

while( true ){
    wait_for_event();
    write_to_fifo("cmd");
}

и написал другую программу:

while(true){
    system(read_from_pipe());
}

но это не помогает, потому что если производитель (1-я программа) пишет быстрее, чем потребитель (вторая программа), тогда потребитель пропускает некоторые данные!

Есть ли способ справиться с этой проблемой?

Ответ 1

Вы должны вернуть код в его первоначальную форму — то есть одна программа, вызывающая вторую программу — за исключением того, что вы вызываете вызов system(3) вызовом popen(3). Теперь вызывающая программа может чередовать вызовы для проверки событий с помощью строк чтения из внешней программы.

Механизм трубы Unix гарантирует, что медленный потребитель заставит быстрого продюсера ждать при записи, когда труба будет заполнена.

Вы также можете просмотреть функцию fileno(3) в сочетании с select(2) или poll(2), чтобы сделать чтение из внешней программы асинхронным, чтобы он никогда не блокировал вызывающую программу.

Ответ 2

Если вам нужно только количество событий, вы можете получить глобальный счетчик. Чтобы избежать условий гонки, вам может потребоваться использовать семафор вместо этого. Конечно, вам нужно будет иметь два потока.

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

Ответ 3

Вы можете запустить свою внешнюю программу явно, используя fork (2), execve (2), waitpid (2) и, возможно, pipe (2), dup2 (2) и другие системные вызовы.

Вам, вероятно, нужен цикл событий. Вы можете использовать poll (2) syscall (или, возможно, библиотеку циклов событий, например libev, который использует poll).

Я настоятельно рекомендую взять часы, чтобы прочитать хорошую передовую книгу программирования Linux перед кодированием.