Evgenii Legotckoi
Evgenii LegotckoiМамыр 15, 2016, 7:11 Т.Ж.

Qt/C++ - Сабақ 048. QThread – moveToThread көмегімен ағындармен жұмыс

Алдыңғы мақалада біз тек ағындармен жұмыс істеу туралы және ағынның өзін теңшеу үшін көбірек қызмет ететін нұсқада ғана тоқталдық, бірақ оны қолдануға болады. ағындарға тікелей қатысы жоқ бөгде жұмыстарды орындау. Яғни, QThread мұрасы бар және run() әдісін қайта анықтайтын нұсқа.

Енді біз ExampleObject сыныбын жасаймыз, оның нысандары moveToThread() әдісі арқылы бөлек ағындарға тасымалданады және сол ағындарда орындалады. Ал пайдалы жұмыс осы сыныпта анықталатын run(), слот әдісімен орындалады. Маңыздысы, объект класы QObject мұрагері болады.

run() әдісіндегі жұмыс циклді түрде орындалуы үшін while циклін қолданамыз, оны bool m_running айнымалысы арқылы басқарамыз. Жұмыс ыңғайлылығы үшін бұл айнымалы, біз оны * Q_PROPERTY ретінде анықтаймыз. Ал, жұмыс аяқталғанда, біз finished() * сигналын шығарамыз.


Жұмыс алгоритмі

Ал енді тікелей ағынмен және объектімен жұмыс істеуге көшейік. Жұмыс алгоритмі келесідей болады:

  1. QThread нысанын және ExampleObject; класының объектісін жасаңыз.
  2. QThread::started() сигналын ExampleObject::run(); әдісіне қосыңыз
  3. Пайдалы жұмыс аяқталғанда ағынның орындалуын тоқтату үшін ExampleObject::finished() сигналын QThread::terminate(), ұяшығына қосамыз;
  4. Циклды қосу үшін m_running айнымалысын true, мәніне орнатыңыз, әйтпесе әдіс дереу тоқтатылады;
  5. start(); әдісі арқылы жіпті бастаңыз
  6. Объектінің пайдалы жұмысын орындауды аяқтау қажет болғанда m_running айнымалысын жалған мәніне қойыңыз. run() әдісінің орындалуы және нысан өмір сүретін ағын автоматты түрде және дұрыс аяқталады.

Жоба құрылымы және қолданбаның көрінісі

  • ThreadLessonTwo.pro - жоба профилі;
  • exampleobject.h - ағынға берілетін нысанның тақырып файлы;
  • exampleobject.cpp - ағынға берілетін нысанның бастапқы код файлы;
  • mainwindow.h - қолданбаның негізгі терезесінің тақырып файлы;
  • mainwindow.cpp - қолданбаның негізгі терезесі үшін бастапқы код файлы;
  • mainwindow.ui - қолданбаның негізгі терезесінің пішін файлы;
  • main.cpp - негізгі функциясы бар бастапқы код файлы.

Қолданба екі нысанды және екі ағынды анықтайды. Қолданба интерфейсін пайдалана отырып, біз qDebug() шығысында көрсетілетін кейбір ақпаратты орнатамыз, сонымен қатар ағындарды бастаймыз және тоқтатамыз.

Қолданба терезесін құру процесі бейне оқулықта көрсетілген.

exampleobject.h

Алдымен нысанның тақырып файлының мазмұнын қарастырайық. Бұл файл үш Q_PROPERTY сипатын жариялайды:

  1. run — run() әдісінде циклды басқару үшін пайдаланылатын және сәйкесінше объектінің пайдалы жұмысының аяқталуына әсер ететін айнымалы.
  2. хабарлама – негізгі қолданба терезесінен qDebug() шығару үшін жіберілетін жол
  3. message_2 – екінші жол, ол qDebug() ішінде де көрсетіледі, бірақ екінші ағынға өту үшін де пайдаланылады.

Тақырып файлы сонымен қатар слот әдісін run(), сигнал finished() және айнымалы int count, жариялайды.

#ifndef EXAMPLEOBJECT_H
#define EXAMPLEOBJECT_H

#include <QObject>

class ExampleObject : public QObject
{
    Q_OBJECT
    // Свойство, управляющее работой потока
    Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged)
    // Первое сообщение в объекте
    Q_PROPERTY(QString message READ message WRITE setMessage NOTIFY messageChanged)
    // Второе сообщение, которое будем передавать через сигнал/слот во второй объект
    Q_PROPERTY(QString message_2 READ message_2 WRITE setMessage_2 NOTIFY message_2Changed)

    bool m_running;
    QString m_message;
    QString m_message_2;
    int count;  // Счётчик, по которому будем ориентироваться на то,
                // что потоки выполняются и работают

public:
    explicit ExampleObject(QObject *parent = 0);
    bool running() const;
    QString message() const;
    QString message_2() const;

signals:
    void finished();    // Сигнал, по которому будем завершать поток, после завершения метода run
    void runningChanged(bool running);
    void messageChanged(QString message);
    void message_2Changed(QString message_2);
    void sendMessage(QString message);

public slots:
    void run(); // Метод с полезной нагрузкой, который может выполняться в цикле
    void setRunning(bool running);
    void setMessage(QString message);
    void setMessage_2(QString message_2);
};

#endif // EXAMPLEOBJECT_H

exampleobject.cpp

Біздің барлық қызығушылық run() әдісіне түседі, мұнда while циклінде санауыш санақ ұлғайып, ақпарат m_message, хабарламасымен көрсетіледі. m_message_2 және берілген санауыш m_running айнымалысы false мәніне орнатылғанша дейін. Циклдан шыққаннан кейін, run() әдісінің орындалуы аяқталғанда, finished() сигналы шығарылады, ол осы нысан орналасатын ағынды тоқтатады.

#include "exampleobject.h"
#include <QDebug>

ExampleObject::ExampleObject(QObject *parent) :
    QObject(parent),
    m_message(""),
    m_message_2("")
{

}

bool ExampleObject::running() const
{
    return m_running;
}

QString ExampleObject::message() const
{
    return m_message;
}

QString ExampleObject::message_2() const
{
    return m_message_2;
}

// Самый важный метод, в котором будет выполняться "полезная" работа объекта
void ExampleObject::run()
{
    count = 0;
    // Переменная m_running отвечает за работу объекта в потоке.
    // При значении false работа завершается
    while (m_running)
    {
        count++;
        emit sendMessage(m_message); // Высылаем данные, которые будут передаваться в другой поток
        qDebug() << m_message << " " << m_message_2 << " " << count;
    }
    emit finished();
}

void ExampleObject::setRunning(bool running)
{
    if (m_running == running)
        return;

    m_running = running;
    emit runningChanged(running);
}

void ExampleObject::setMessage(QString message)
{
    if (m_message == message)
        return;

    m_message = message;
    emit messageChanged(message);
}

void ExampleObject::setMessage_2(QString message_2)
{
    if (m_message_2 == message_2)
        return;

    m_message_2 = message_2;
    emit message_2Changed(message_2);
}

mainwindow.h

Қолданбаның негізгі терезесінің тақырып файлы ағындарда орындалатын нысандарға хабарлама жазу үшін түймелерді басып өңдеуге арналған ұяшықтарды, сонымен қатар ағындарды бастау және тоқтату үшін ұяшықтарды жариялайды. Сонымен қатар, біз ExampleObject класының екі нысанын және QThread класының екі нысанын жариялаймыз.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QThread>
#include "exampleobject.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_write_1_clicked();  // Слот для записи данных из lineEdit_1 в первый объект первого потока
    void on_write_2_clicked();  // Слот для записи данных из lineEdit_1 во второй объект второго потока
    void on_start_clicked();    // Слот для запуска потоков
    void on_stop_clicked();     // Слот для остановки потоков

private:
    Ui::MainWindow *ui;
    QThread thread_1;       // Первый поток
    QThread thread_2;       // Второй поток
    ExampleObject exampleObject_1;  // первый объект, который будет работать в первом потоке
    ExampleObject exampleObject_2;  // второй объект, который будет работать во втором потоке
};

#endif // MAINWINDOW_H

mainwindow.cpp

Ал енді барлық алдыңғы кодты негізгі қолданба терезесінің бастапқы кодында жұмыс істейтін қолданбаға біріктірейік. Бұл сыныптың конструкторында, ең басында айтылғандай, ағындардың started() сигналдарын сынақ нысандарымыздың run() ұяшықтарына және * finished(), ағын ұяшықтарына сигналдар terminate(), run() әдісі аяқталған кезде ағындарды тоқтату үшін. *

Біз сондай-ақ exampleObject_1 нысанының хабарламасын жіберу үшін сигналды exampleObject_2 хабарламаны орнату ұяшығына қосамыз. Бірақ ақпарат жіберілу үшін *Qt::DirectConnection арқылы өту керек. * объектілердің тікелей байланысын орнататын және [сигналдар мен ұялар] жүйесі (https://evileg.com/ru/post/87/) арқылы ақпаратты жіберуді орындауға мүмкіндік беретін қосылу әдісіне бесінші аргумент ретінде жалауша ).

Нысандарды ағындарға тасымалдау үшін moveToTrhead(). әдісін пайдалану керек.

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // Запуск выполнения метода run будет осуществляться по сигналу запуска от соответствующего потока
    connect(&thread_1, &QThread::started, &exampleObject_1, &ExampleObject::run);
    connect(&thread_2, &QThread::started, &exampleObject_2, &ExampleObject::run);
    // Остановка потока же будет выполняться по сигналу finished от соответствующего объекта в потоке
    connect(&exampleObject_1, &ExampleObject::finished, &thread_1, &QThread::terminate);
    connect(&exampleObject_2, &ExampleObject::finished, &thread_2, &QThread::terminate);
    // коннект для передачи данных из первого объекта в первом потоке, ко второму объекту во втором потоке
    connect(&exampleObject_1, &ExampleObject::sendMessage, &exampleObject_2, &ExampleObject::setMessage_2, Qt::DirectConnection);
    exampleObject_1.moveToThread(&thread_1);    // Передаём объекты в соответствующие потоки
    exampleObject_2.moveToThread(&thread_2);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_write_1_clicked()
{
    // Устанавливаем текст в первый объект в первом потоке
    exampleObject_1.setMessage(ui->lineEdit_1->text());
}

void MainWindow::on_write_2_clicked()
{
    // Устанавливаем текст во второй объект во втором потоке
    exampleObject_2.setMessage(ui->lineEdit_2->text());
}

void MainWindow::on_start_clicked()
{
    // Запуск потоков
    exampleObject_1.setRunning(true);
    exampleObject_2.setRunning(true);
    thread_1.start();
    thread_2.start();
}

void MainWindow::on_stop_clicked()
{
    // Остановка потоков через завершение выполнения методов run в объектах
    exampleObject_1.setRunning(false);
    exampleObject_2.setRunning(false);
}

Қорытынды

Қолданбаны іске қосу нәтижесінде сіз ағындардағы объектілердің параллель жұмысын, сондай-ақ ақпаратты бір ағыннан екіншісіне тасымалдауды көрсететін qDebug() келесі нәтижесін алуға болады.

"thread 1"   ""   11422
"thread 2"   "thread 1"   11446
"thread 1"   ""   11423
"thread 2"   "thread 1"   11447
"thread 1"   ""   11424
"thread 2"   "thread 1"   11448
"thread 1"   ""   11425
"thread 2"   "thread 1"   11449
"thread 1"   ""   11426
"thread 2"   "thread 1"   11450
"thread 1"   ""   11427
"thread 2"   "thread 1"   11451

Жобаны келесі сілтемеден жүктеп алуға болады: Тақырып сабағы

Бейне оқулық

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

d
  • Шілде 10, 2017, 11:02 Т.Ж.

У меня происходит переполнение счетчика count, появляется ошибка malloc(): memory corruption (fast). Не подскажите, как с этим бороться?

Evgenii Legotckoi
  • Шілде 10, 2017, 11:34 Т.Ж.

А что делали? Повторяете урок или как? Пытались просто скачать проект в конце статьи и запустить?

t
  • Там. 7, 2017, 5:12 Т.Ж.

Взял Ваш пример для Qt4.8 (не спрашивайте почему). переписал связь сигнал/слот след. образом:

    // Запуск выполнения метода run будет осуществляться по сигналу запуска от соответствующего потока
    QObject::connect(&thread_1,        SIGNAL(started()),
                     &exampleObject_1, SLOT(run()));
    QObject::connect(&thread_2,        SIGNAL(started()),
                     &exampleObject_2, SLOT(run()));
    //connect(&thread_1, &QThread::started, &exampleObject_1, &ExampleObject::run);
    //connect(&thread_2, &QThread::started, &exampleObject_2, &ExampleObject::run);
    // Остановка потока же будет выполняться по сигналу finished от соответствующего объекта в потоке

    QObject::connect(&exampleObject_1,        SIGNAL(finished()),
                     &thread_1, SLOT(terminate()));
    QObject::connect(&exampleObject_2,        SIGNAL(finished()),
                     &thread_2, SLOT(terminate()));
    //connect(&exampleObject_1, &ExampleObject::finished, &thread_1, &QThread::terminate);
    //connect(&exampleObject_2, &ExampleObject::finished, &thread_2, &QThread::terminate);
    // коннект для передачи данных из первого объекта в первом потоке, ко второму объекту во втором потоке
    QObject::connect(&exampleObject_1,        SIGNAL(sendMessage(QString)),
                     &exampleObject_2,        SLOT(setMessage_2(QString)));
    //connect(&exampleObject_1, &ExampleObject::sendMessage,
    //        &exampleObject_2, &ExampleObject::setMessage_2, Qt::DirectConnection);

В итоге получаю

"thread 1" "" 1752

"thread 2" "" 1747

"thread 1" "" 1753

"thread 2" "" 1748

"thread 1" "" 1754

т.е. связь между потоками не работает.


Вижу еще волшебное слово Qt::DirectConnection, пробовал добавить - нет результата

Добавил  еще в pro файл запись CONFIG += no_keywords - тоже не помогло

Что подскажите


PS: я нубер в Qt и плюсах

Evgenii Legotckoi
  • Там. 7, 2017, 5:30 Т.Ж.

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

P/S/ Если соберетёсь кидать весь код, то создавайте тогда новую тему на форуме. Там есть возможность прикрепить архив с проектом к теме и сообщениям. В комментариях под статьёй не стоит постить большие куски кода.

Форум здесь .
t
  • Там. 7, 2017, 6:48 Т.Ж.

В остальном код как и Вашем примере

Evgenii Legotckoi
  • Там. 7, 2017, 8:37 Т.Ж.

Тогда мне больше нечего Вам сказать. Давно уже не работал с Qt 4.8 и приниципиально не работаю с ним сейчас.

t
  • Там. 15, 2017, 9:49 Т.Ж.

В qt5.6 всё нормально заработало. С 4.8 - нет

Evgenii Legotckoi
  • Там. 15, 2017, 10:32 Т.Ж.

Нууу... тут уже вопрос к самому Qt4.8. Если честно, идей нет, да и копаться в deprecated коде желания тоже нет.

m
  • Қыр. 4, 2017, 10:57 Т.Ж.

В моем коде с двумя потоками и выводом сообщений в textEdit при использовании Qt::DirectConnection падает в "The program has unexpectedly finished" через 10-20 сообщений.  При использовании Qt::QueuedConnection, работает.

Все же как правильно использовать ?
Нашел на другом форуме:
  • Qt::DirectConnection — сигнал обрабатывается сразу вызовом соответствующего метода слота
  • Qt::QueuedConnection — сигнал преобразуется в событие и ставится в общую очередь для обработки
  • Qt::AutoConnection — это автоматический режим, который действует следующим образом: если отсылающий сигнал объект находится в одном потоке с принимающим его объектом, то устанавливается режим Qt::DirectConnection , в противном случае — режим Qt::QueuedConnection . Этот режим ( Qt::AutoConnection ) определен в методе connection() по умолчанию.
Evgenii Legotckoi
  • Қыр. 4, 2017, 2:31 Т.Қ.

В принципе все варианты возможны, зависит от ситуации.
Наиболее правильным по максимому использовать Qt::AutoConnection. Если что-то по какой-то причине не работает, то разбираться в чём причина и возможно переходить на Qt::DirectConnection , при данном методе слот будет вызываться сразу же, юез постановки в очередь событий. Иногда может потребоваться, чтобы дать приоритет вызову слота. Ведь слоты вызываются в той последовательности, как они был подключены в коде.
Тут уже возникает вопрос в потокобезопасности. Поэтому сложный код следует блокировать мьютексами.Теми же самыми QMutexLocker и QMutex, например,

int complexFunction(int flag)
{
    QMutexLocker locker(&mutex);

    // ToDo something
    return retVal;
}
В данном случае mutex является объектов класса QMutex, который объявлен в заголовке класса. Можете проверить у себя работу вашего класса с использование QMutex и Qt::DirectConnection .
m
  • Қыр. 5, 2017, 12:34 Т.Ж.

В том и дело что хотел без мютексов обойтись. т.е. суть проблемы есть старая программа, рабочая и три потока в ней  A-B-(C1...Cn) .

A - поток основной программы;
B - поток для QModbusTcpServer;
С1...Cn - потоки опроса приборов по протоколу xxx [RTU];

Задача передать из потоков собранные данные потоков C1...Cn в один JSON контейнер и отправить в QWebSocketServer.
В QWebSocketServer создал слот (для отладки и в MainWindow) привязал сигналы из C1...Cn,  передаю простой тип QString.

Вопрос , на ваш взгляд потокобезопасно так делать или нет ? Ну и как писал Qt::DirectConnection вызывает глюк, без него работает.
P.S. Qt 5.6.1
Evgenii Legotckoi
  • Қыр. 5, 2017, 2:27 Т.Ж.

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

  • Qt::QueuedConnection является потокобезопасным вариантом и информация не портится при передаче данных потому, что все сигналы отправляют информацию в очередь сообщений и информация обрабатывается поочерёдно. Это актуально для передачи информации между несколькими потоками.
  • Qt::DirectConnection используется тогда, когда и отправитель сигнала и получатель находятся в одном потоке, поскольку такая передача информации будет потокобезопасной. Всё равно другой код не начнёт работу с текущим слотом, пока слот не завершится. Но это не значит, что такое соединение нельзя использовать при передачи информации между потоками. Только в данном случае нужно обезопаситься мьютексами. Тем более, что их реализация позволяет это делать в одну строку в методе.
Поэтому у вас всё заработало с Qt::QueuedConnection и сломалось с Qt::DirectConnection, очевидно потоки конкурировали друг с другом и получилось, что была испорчена память.

Поэтому в вашем случае работайте без Qt::DirectConnection , и подумайте над использованием мьютексов. Если начнёт падать и с Qt::QueuedConnection , то стоит подумать над подключением мьютексов.
g
  • Маусым 9, 2018, 7:37 Т.Ж.

Возможно таким же способом передать туда QTcpSocket?

Evgenii Legotckoi
  • Маусым 12, 2018, 2:42 Т.Ж.

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

ИВ
  • Наурыз 16, 2021, 1:07 Т.Қ.

Не получается сделать connect, получаю гору ошибок. В чем может быть дело ?

Evgenii Legotckoi
  • Шілде 2, 2021, 6:35 Т.Ж.

connect(&thread01, &QThread::started, Server, &myserver::run);

AC
  • Ақп. 28, 2023, 4:26 Т.Ж.
  • (өңделген)

Ввожу 1 в Write 1, ввожу 2 в Write 2, нажимаю Start и сразу Stop. Сначала вижу очень много одинаковых строк, а потом сообщение об ошибке. При этом программа не крашится, но предупреждение настораживает... Почему так? Неужели надо &QThread::terminate заменить на &QThread::quit ? Вот что у меня вышло после. Варнинг перестал сыпаться...
Ubuntu 22, Qt 6.

"1" "" 212463
"2" "1" 253535
"1" "" 212464
"1" "" 212465
"2" "1" 253536
"2" "1" 253537
Qt has caught an exception thrown from an event handler. Throwing
exceptions from an event handler is not supported in Qt.
You must not let any exception whatsoever propagate through Qt code.
Qt has caught an exception thrown from an event handler. Throwing
exceptions from an event handler is not supported in Qt.
You must not let any exception whatsoever propagate through Qt code.

ThreadLessonTwo problem

Evgenii Legotckoi
  • Наурыз 13, 2023, 8:08 Т.Ж.

Вообще, правильнее использоать quit, поскольку terminate - это более жёсткий вариант, на тот случай, если поток схватил deadlock.
Так что в итоге вы правильно всё исправили. Статья старая, на тот момент я делал больше глупых ошибок :-)

AC
  • Маусым 16, 2023, 9:55 Т.Ж.

После того, как было сделано

exampleObject_1.moveToThread(&thread_1);

Объект exampleObject_1 стал жить в своей ните, а не в той же, где живет MainWindow

Почему же в методе MainWindow::on_write_1_clicked()
Можно обращаться к методам exampleObject_1?
Разве могут взаимодействовать объекты из разных нитей как-то, кроме как через сигнал-слоты?

AC
  • Маусым 17, 2023, 10:03 Т.Ж.

В продолжение моего предыдыщуего поста.

Похоже, нельзя обращаться к полям и методам объекта А из объекта Б, если они в разных нитях живут. Поэтому вместо

exampleObject_1->setRunning(false);

Следует писать

thread_1->requestInterruption();

А вместо

    while (m_running)
    {
        count++;
        emit sendMessage(m_message); // Высылаем данные, которые будут передаваться в другой поток
        qDebug() << m_message << " " << m_message_2 << " " << count;
    }
    emit finished();

Стоит писать

    while(1)
    {
        if(QThread::currentThread()->isInterruptionRequested()){
            goto exit_LABEL;
        }
        count++;
        emit sendMessage(m_message); // Высылаем данные, которые будут передаваться в другой поток
        qDebug() << m_message << " " << m_message_2 << " " << count;
    }
exit_LABEL:;
    emit finished();

И на всякий случай выскажусь по поводу конструктора ExampleObject::ExampleObject(). Сейчас он пустой, но нужно проговорить. В этом конструкторе ни в коем случае нельзя выделять память из кучи (делать new), подробности тута см "NEVER allocate heap objects (using new)".

Evgenii Legotckoi
  • Маусым 19, 2023, 3:56 Т.Ж.

Там всё равно есть ссылочная информация на этот объект, просто... да... всё может посыпаться в более сложной логике. Пример очень старый, может быть неактуален или в чём-то неправилен в настоящее время.

AC
  • Там. 20, 2023, 5:52 Т.Ж.

"Запуск выполнения метода run будет осуществляться по сигналу запуска от соответствующего потока"
Мой душнила шепчет, что корректнее было бы написать
"Запуск выполнения метода run будет осуществляться по сигналу запуска от соответствующего объекта (thread_1 или thread_2) QThread."
Почему это важно? Может показаться, что существуют какие-то статические сигналы, которые способен emit непосредственно класс QThread. По аналогии со статическими методами...
Верно?

Evgenii Legotckoi
  • Там. 20, 2023, 9:53 Т.Ж.

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

AC
  • Там. 24, 2023, 8:49 Т.Ж.

Вот тут можно посмотреть аналогичный современный проект (правда с одной дополнительной нитью).

AC
  • Қыр. 5, 2023, 3:37 Т.Ж.

Я поясню свой вопрос. Выше я писал
"Почему же в методе MainWindow::on_write_1_clicked()
Можно обращаться к методам exampleObject_1?
Разве могут взаимодействовать объекты из разных нитей как-то, кроме как через сигнал-слоты?"

Вот чего я боюс:
"Ещё совсем уж вскользь упомяну, что реализация SMP в процессорах Интел совершенно всепрощающа и гарантирует программисту, что все процессоры видят память одинаково, хотя и имеют раздельные кеши. То есть обеспечивают так называемую когерентность кешей процессоров в многопроцессорной системе.
Это не везде так. Есть процессоры, в которых надо предпринимать специальные усилия для того, чтобы данные гарантированно были синхронизированы между процессорами. Или явно выключать кеширование для страниц памяти, в которых лежат данные, доступные нескольким процессорам. Это уже тема для совершенно отдельного разговора, здесь я лишь упомянул для полноты."

Ответ Евгения "Там всё равно есть ссылочная информация на этот объект" как-то не очень успокаивает... Есть ссылка на область (какой-то) памяти, с чего бы вдруг одной и той же для разных-то нитей?..

Evgenii Legotckoi
  • Қыр. 6, 2023, 7:18 Т.Ж.

Разве могут взаимодействовать объекты из разных нитей как-то, кроме как через сигнал-слоты?"

Могут. Выполняя оператор new , Вы выделяете под объект память в куче (heap), и если вы передаёте указатель на этот объект в 10 потоков, то код во всех 10-ти потоках может работать с этим указателем и модифицировать объект. В этом случае важным является защищать процесс записи мьютексами, чтобы не возникло состояниее гонки и данные не накрылись медным тазом. А сигнал слотовое соединение - это механизм потокобезопасной передачи данных, но это абсолютно не означает, что через это соединение нельзя передать указатель на объект в другом потоке, и не означает, что не нужно записываемые данные защищать мьютексами.

А касательно той статьи на Хабре, то это системное программирование на микроконтроллерах с использованием чистого Си, судя по коду, может я и ошибаюсь, но меня берут сомнения, что там примеры на С++. Да и автор в комментариях упоминает о Atmega 128.
Поэтому и рассуждение на тему организации памяти в процессоре исходя из статьи для систем реального времени на микроконтроллерах хоть и применимо для десктоп приложений, для которых в первую очередь разрабатывался Qt, тем не менее всё же выглядит высасыванием проблемы из пальца. Хотя бы потому, что в таком случае нужно уже говорить относительно конкретной модели процессора, на котором происходит разработка. В противном случае разговор является беспредметным.

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
Г

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:66ұпай,
  • Бағалау ұпайлары-1
t

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:33ұпай,
  • Бағалау ұпайлары-10
t

Qt - Тест 001. Сигналы и слоты

  • Нәтиже:52ұпай,
  • Бағалау ұпайлары-4
Соңғы пікірлер
G
GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssrАқп. 8, 2024, 6:43 Т.Қ.
Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
F
FynjyШілде 22, 2024, 4:15 Т.Ж.
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
BlinCT
BlinCTМаусым 25, 2024, 1 Т.Ж.
Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
BlinCT
BlinCTМамыр 5, 2024, 5:46 Т.Ж.
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
Evgenii Legotckoi
Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

Бізді әлеуметтік желілерде бақылаңыз