Я наткнулся на этот вопрос и был очень впечатлен этот ответ.

Мне бы очень хотелось последовать советам из этого ответа, но я не представляю, как это сделать. Как избежать многопоточности?

Часто возникают ситуации, когда необходимо иметь дело с разными вещами одновременно (например, с разными аппаратными ресурсами или сетями), но в то же время им нужен доступ к общим данным (например, конфигурациям, данным для работы и т. Д.). Как это можно решить в однопоточном режиме без использования каких-либо огромных конечных автоматов или циклов событий?

Я знаю, что это огромная тема, на которую невозможно ответить в целом на такой платформе, как Stackoverflow. Я думаю, мне действительно стоит прочитать рекомендованную книгу из упомянутого ответа, но сейчас я хотел бы прочитать здесь некоторые комментарии.

Возможно, стоит отметить, что меня интересуют решения на C. Более высокие языки, такие как Java, C ++ и особенно фреймворки, такие как Qt или подобные, значительно упрощают это, но как насчет чистого C?

Любой вклад очень ценится. Спасибо всем заранее

2
exilit 5 Мар 2015 в 13:57

3 ответа

Лучший ответ

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

Предположим, у вас есть приложение, которое должно обрабатывать ввод данных пользователем, данные, полученные через сокет, события таймера и сигналы, например:

  • Один многопоточный дизайн будет заключаться в том, чтобы порождать разные потоки для ожидания различных источников событий и синхронизации их действий с некоторым глобальным состоянием по мере поступления событий. Это часто приводит к беспорядочной логике синхронизации и завершения.

  • Однопоточная конструкция должна иметь унифицированный цикл обработки событий, который принимает все типы событий и обрабатывает их в том же потоке, в котором они поступают. В системах * nix это можно сделать, например, select(2), poll(2) или epoll(7) (последнее относится к Linux). В последних версиях Linux также есть signalfd(2), timerfd (timerfd_create(2)) и eventfd(2) для точной подгонки дополнительных типов событий в эту модель, а в других модулях вы можете использовать различные приемы, включающие например pipe(2) для сигнализации событий. Хорошая библиотека, которая абстрагирует большую часть этого, - это libevent, который также работает на других платформах.

Помимо того, что не нужно сразу иметь дело с многопоточностью, подход с использованием цикла событий также позволяет добавлять многопоточность позже, если это необходимо для производительности или по другой причине: вы просто позволяете обработчику событий создавать потоки для определенных событий. Хранение всей обработки событий в одном месте часто значительно упрощает дизайн приложения.

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

3
Ulfalizer 5 Мар 2015 в 23:58

Вы можете реализовать параллельные задачи, используя сопрограммы. Затем вам нужно явно передать управление (процессор) другой сопрограмме. Это не будет выполнено автоматически прерыванием после небольшой задержки.

http://en.wikipedia.org/wiki/Coroutine

1
chmike 5 Мар 2015 в 11:06

Подробнее о продолжениях и стиль передачи продолжения (и преобразование CPS).

CPS-преобразование может быть систематическим способом имитации многопоточности.

Вы можете ознакомиться с CPC ( Continuation Passing C , Юлиуш Хробочек и Габриэль Кернейс), который также является источником для трансформатора C. Вы также можете прочитать старую книгу Аппеля: Компиляция с продолжениями и книга Queinnec Lisp In Small Pieces < / em>

Также читайте подробнее о циклах событий, обратные вызовы, закрытия, стеки вызовов, хвостовые вызовы. Эти понятия связаны с вашими проблемами.

См. Также (почти устаревший) setcontext (3) Linux функции и функций ожидания в циклах событий см. в этом.

2
Community 23 Май 2017 в 12:23