Является ли эта комбинация сигналов и потоков мудрой идеей?На другом форуме кто-то советовал кому-то другому не «идти по этому пути».
Вроде бы звук.Можете ли вы предоставить ссылку на другой поток?Они объясняли свои аргументы?
Есть ли поблизости потенциальные подводные камни, которые я не смог увидеть?
Если они такие, я тоже их не вижу.Вам нужно позаботиться о том, чтобы уведомления были поточно-ориентированными (запуск сигнала не переключает контексты потока, на ваш GuiClass::slot_data_changed
следует вызывать из всех других потоков.
Реалистичны ли мои ожидания, что будет проще использовать класс GUI для предоставления веб-интерфейса или QT, VTK или любого другого окна?
Это будет непросто. Исправитьэто, вам нужно было бы сделать так, чтобы ваше уведомление переключало контексты потоков. Вот что я бы сделал:
Пусть ваш GuiClass
будет абстрактным базовым классом, реализующим свою собственную очередь сообщений. Когда GuiClass::slot_data_changed
вызываетсяваши потоки, вы блокируете мьютекс и публикуете копию полученного уведомления во внутренней (private:
) очереди сообщений. В потоке GuiClass
вы создаете функцию, которая блокирует мьютекс и ищет уведомления в очереди.Эта функция должна выполняться в потоке клиентского кода (в потоке конкретных классов, которые вы специализируете на аннотации GuiClass
).
Преимущества:
- ваш базовый класс инкапсулирует и изолирует переключение контекста потока, прозрачно для его специализаций.
Недостатки:
Являются ли мои ожидания реалистичными, что будет легче использовать мой класс GUI для предоставления веб-интерфейса или QT, VTK или любого другого окна?
Не видит, но этоне просто.Помимо переключения контекста потока, могут быть и другие проблемы, которые я пропускаю в данный момент.
Есть ли более умная альтернатива (как и другие библиотеки повышения), которую я пропустил?
Не другие библиотеки повышения, но то, как вы пишете свои потоки, нехорошо: объединения выполняются последовательно в вашем коде.Чтобы иметь только один join
для всех потоков, используйте boost :: thread_group.
Вместо:
boost::thread t1(r1, 3);
boost::thread t2(r2, 1);
boost::thread t3(r3, 2);
boost::thread t4(r4, 2);
boost::thread t5(r5, 3);
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
у вас будет:
boost::thread_group processors;
processors.create_thread(r1, 3);
// the other threads here
processors.join_all();
Редактировать : Контекст потока - это все, что является специфическим для конкретного работающего потока (хранилище, специфичное для потока, стек этого потока, любые исключения, выданные в контексте этого потока и т. Д.).
Если у вас в приложении есть различные контексты потоков (несколько потоков), вам нужно синхронизировать доступ к ресурсам, созданным в контексте потока и доступным из разных потоков (используя блокирующие примитивы).
Например, предположим, у вас естьa
, экземпляр class A
[работающий в потоке tA], выполняющий какую-то работу, и b
, экземпляр class B
[работающий в контексте потока tB] и b
хочет что-то сказать a
.
Часть "хочет сказать a
что-то" означает, что b
хочет вызвать a.something()
, а a.something()
будет вызвано в контексте tB (в стеке потока B).
К чДля этого (чтобы запустить a.something()
в контексте tA), вам нужно переключить контекст потока .Это означает, что вместо b
, говорящего a
"run A::something()
", b
сообщает a
"run A ::thing ()` в вашем собственном контексте потока ".
Классическая реализацияшаги:
b
отправляет сообщение a
изнутри tB
a
опрашивает сообщения изнутри tA
Когда a
находит сообщение от b
, он запускает a.something () в пределах tA.
Это переключение контекстов потоков (выполнение A::something
будет выполняться в tA вместо tB, как это было бы, если бы вызывалось непосредственно из b
).
По ссылке, которую выпри условии, что, кажется, это уже реализовано boost::asio::io_service
, поэтому, если вы используете это, вам не нужно реализовывать это самостоятельно.