Безопасен ли этот метод межпотоковой связи? - PullRequest
4 голосов
/ 28 сентября 2011

У меня есть 3 объекта (унаследованных от QObject), каждый из которых содержит отдельный std::list. Каждый объект создается в основном потоке графического интерфейса (без родительского элемента), а затем помещается в собственный поток (используя Qt QObject::moveToThread()).

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

Obj 1: потребитель данных. Он вылетает из списка (если есть данные) для использования. Он также имеет доступный слот, так что другие потоки могут передавать данные в него. Никакой другой объект не может получить доступ к этому списку напрямую только к исходному классу QObject.

Obj 2: источник данных. Он помещает данные в свой список. У него есть СЛОТЫ, доступные для других, чтобы «пинговать» его для данных, которые, в свою очередь, будут выдавать данные извлечения СИГНАЛА из своего списка. Никакой другой объект не может получить доступ к этому списку напрямую.

Obj 3: создает данные для obj 1 и использует данные из obj 2. Он имеет свои собственные внутренние структуры данных, которые отслеживают данные, отправленные в obj 1, и данные, поступающие из obj 2. Это, наконец, подтолкнет оба набора данных к некоторому QwtPlots после того, как он сделает некоторый анализ.

Obj's 1 и 2 являются критическими в режиме реального времени и используют «синхронизацию» в стиле QueryPerformanceCounter, которая, по существу, будет отнимать процессор каждый раз во время работы. Они запускают QCoreApplication::processEvents() каждый цикл для обработки событий, которые происходят через.

Это нормальный способ управления межпотоковым обменом данными? Если это не так, где дыры и как бы вы их исправили? Я понимаю, что это создаст много «копий» данных, летающих вокруг, но раздувание памяти на данный момент не является проблемой.

заранее спасибо:)

1 Ответ

2 голосов
/ 28 сентября 2011

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

Obj 1: Потребитель данных,Он вылетает из списка (если есть данные) для использования.Он также имеет доступный слот, так что другие потоки могут передавать данные в него.Никакой другой объект не может получить доступ к этому списку напрямую только к исходному классу QObject.

Если этот слот подключен к сигналам в других потоках (например, Obj 3) с использованием очереди или автоматического типа подключения, то Obj1, вероятно, безопасно.Если слот вызывается напрямую из других потоков, то он, очевидно, не является поточно-ориентированным, если вы явно не синхронизируете все.

Obj 2: Источник данных.Он помещает данные в свой список.У него есть СЛОТЫ, доступные для других, чтобы «пинговать» его для данных, которые, в свою очередь, будут выдавать данные извлечения СИГНАЛА из своего списка.Никакой другой объект не может получить доступ к этому списку напрямую.

Вы не упоминаете, как реализовано "пингование" или какие потоки вызывают эти слоты.Если другие потоки вызывают их напрямую и если pinging предполагает доступ к внутреннему std :: list, то у вас проблемы.Если эти слоты вызываются только через очереди или автоматические соединения (к какому-либо сигналу в Obj 3, например), то это нормально.Если эти слоты являются поточно-ориентированными (например, они помещают сообщение «ping» только во внутреннюю синхронизированную очередь сообщений), то это тоже нормально.Последний способ выглядит как обычная реализация механизма соединений в очереди.

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

void Obj2::ping() {
    if (QThread::currentThread() != this->thread()) {
        // not sure how efficient it is
        QMetaObject::invoke(this, "ping", Qt::QueuedConnection);
        return;
    }
    // thread unsafe code goes here
}
...