Глобальный указатель на объект

105
19 января 2022, 02:10

Какие могут быть подводные камни если сделать глобальный указатель на объект по типу Sensormanager *sensormanager и передать его во второй поток. Определять его видимость через extern в других диалоговых окнах, по типу extern Sensormanager *sensormanager . Цель: иметь возможность сделать связь сигнал - слот из любого диалогового окна или просто сделать обращение к слоту по типу sensormanager->slot со вторым потоком. Или лучше использовать синглет для этих целей?

Answer 1

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

Пусть у вас имеется несколько окон (Главное MainWindow в нем Dialog1, Dialog2, первом диалоге поддиалог Dialog11), а также отдельно поток (ваш номер 2) SensorManager (основной поток приложения мы подразумеваем).

Вариант 1. Можно сделать общие интерфейсы сигналов и слотов через посредника ГУИ и отдельного посредника Логики.

Пусть у нас для ГУИ посредником служит главное окно приложения:

class MainWindow ... {
    MainWindow() {
        connect(&dialog1, SIGNAL(signal1()), 
                this, SIGNAL(signal1FromDialog1()));
        connect(&dialog1, SIGNAL(signal1Dialog11()), 
                this, SIGNAL(signal1FromDialog11()));
        ...
    }
signals:
    void signal1FromDialog1();
    void signal2FromDialog1();
    void signal3FromDialog1(<какие-то аргументы>);
    void signal1FromDialog11(); // ! От Dialog11
    void signal1FromDialog2();
    void signal2FromDialog2(<какие-то аргументы>);
    и так далее
public slots:
    // Для слотов диалога 1
    void callSlot1Dialog1(<аргуенты и без них>) {
        dialog1.callSlot1(...);
    }
    void callSlot2Dialog1(<аргуенты и без них>) { ... }
    // Для слотов поддиалога 1 диалога 1, то есть для Dialog11
    void callSlot3Dialog11(<аргуенты и без них>) {
        dialog1.callDialog11Method1(...);
    }
    // Для слотов диалога 2
    void callSlot1Dialog2(<аргуенты и без них>) {
        dialog2.callSlot1(...)
    }
    void callSlot2Dialog2(<аргуенты и без них>) { ... }
    и так далее
private:
    Dialog1 dialog1;
    Dialog2 dialog2;
    ...
}

Тоже самое для логики:

class Logic : public QObject {
    Q_OBJECT
signals:
    void someSignalFromThread(<Здесь могли бы быть ваши аргументы>);
public slots:
    void callSlotForThread() {
       sensorManager->someSlot();
    }
private:
    SensorManager* sensorManager;
}

Далее мы все это хозяйство сшиваем/соединяем:

void main() {
    MainWindow window;
    Logic logic;
    QObject::connect(&window, SIGNAL(signal1FromDialog1()), 
                     &logic, SLOT(callSlotForThread()));
    еще коннект за маму,
    еще коннект за папу,
    Коннект из логики в окно
    QObject::connect(&logic, SIGNAL(signal1SensorManager()), 
                     &window, SLOT(callSlotForDialog1()));
    еще коннект из логики, (может быть вы добавите третий поток и т.д.)
    ...
    return a.exec();
}

Вариант 2. Мы не делаем общий интерфейс слотов, сигналов, а предоставляем сами объекты окон, диалогов, потоков и тому подобное. Тогда main будет выглядеть так:

void main() {
    MainWindow window;
    Logic logic;
    ...
    QObject::connect(&window.dialog1(), SIGNAL(signal1FromDialog1()), 
                     &logic, SLOT(callSlot1ForThread()));
    QObject::connect(&window.dialog1().dialog11(), SIGNAL(signal1FromDialog11()), 
                     &logic, SLOT(callSlot2ForThread()));
    ИЛИ!
    QObject::connect(&window.dialog1(), SIGNAL(signal1FromDialog1()), 
                     logic.sensorManager(), SLOT(callSlot1()));
    ...
    return a.exec();
}

Вариант 3. Отдельные окна и диалоги и поддиалоги, и отдельное их связывание друг с другом, но для средних (больше 4-5 объектов) и больших приложений это плохая идея.

Надеюсь идея ясна

Answer 2

Какие могут быть подводные камни если сделать глобальный указатель на объект по типу Sensormanager *sensormanager и передать его во второй поток

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

  • обе операции являются атомарными, или

  • выполнение операций синхронизировано друг с другом (для этих целей подходит std::mutex).

Это будет верно для любого объекта (не обязательно глобального), к которому будут иметь доступ два или более потока, так как в C++ любой поток всегда может обратиться к любому объекту, существующему в программе, если адрес этого объекта был каким-либо способом передан этому потоку.

Обеспечьте потоко-безопасность путём добавления мьютексов во все методы чтения/записи объекта.

В этом примере доступ к Object::value_ защищён std::lock_guard<std::mutex>, и два или более потока могут безопасно одновременно вызвать методы set и get.

class Object
{
public:
    void set(const std::string & content);
    std::string get();
private:
    std::string value_;
    std::mutex mtx_;
};
void Object::set(const std::string & content)
{
    std::lock_guard<std::mutex> lock(mtx_);
    value_ = content;
}
std::string Object::get()
{
    std::lock_guard<std::mutex> lock(mtx_);
    return value_;
}
READ ALSO
В React input изменяется jQuery

В React input изменяется jQuery

Два скрипта взаимодействуют друг с другом: один написан на React, другой на jQueryВ React-компоненте есть textarea и есть событие onChange, которое изменяет...

96
Как сделать плавный скролл? [дубликат]

Как сделать плавный скролл? [дубликат]

Есть сайт генератор паролейТам при нажатии на кнопку идет плавный скролл

103
Проверить, является ли выделенный текст жирным? C#

Проверить, является ли выделенный текст жирным? C#

Есть текст в richTextBox1Как проверить, является ли выделенная область жирным текстом?

73
Передать в Invoke параметр с ref

Передать в Invoke параметр с ref

Пытаюсь использовать Invoke для того, чтобы использовать winform-контролы в другом потокеИ один из аргументов у меня по задумке должен быть ref

182