พฤศจิกายน 22, 2017, 10:53:35 am *
ยินดีต้อนรับคุณ, บุคคลทั่วไป กรุณา เข้าสู่ระบบ หรือ ลงทะเบียน
ส่งอีเมล์ยืนยันการใช้งาน?

เข้าสู่ระบบด้วยชื่อผู้ใช้ รหัสผ่าน และระยะเวลาในเซสชั่น
   หน้าแรก   ช่วยเหลือ เข้าสู่ระบบ สมัครสมาชิก  
หน้า: [1]   ลงล่าง
  พิมพ์  
ผู้เขียน หัวข้อ: Qt :: Threads, Signals and Slots  (อ่าน 2328 ครั้ง)
0 สมาชิก และ 1 บุคคลทั่วไป กำลังดูหัวข้อนี้
ShadowMan
Administrator
Hero Member
*****
ออฟไลน์ ออฟไลน์

เพศ: ชาย
กระทู้: 8267


ShadowWares


| |
« เมื่อ: สิงหาคม 26, 2015, 11:20:20 am »

Multi-threading บน GUI application เป็นเรื่องที่ท้ายทายในทุกภาษา โดยเฉพาะอย่างยิ่งเมื่อ Thread ต่างๆ ต้องการเข้าถึง GUI component ซึ่งโดยปกติเป็นของ Main-Thread และเป็น Shared resource อย่างไรก็ตามแต่ละภาษา และละ OSมีเทคนิคเพื่อให้ Thread ต่างๆ เข้าถึง Shared resourceที่แตกต่างกันออกไป สิ่งนี้เป็นเรื่องที่ต้องใช้ความเข้าใจมากในระดับหนึ่งของโปรแกรมเมอร์

ใน Qt Framework อาศัยความสามารถพื้นฐาน ที่ทำให้ Qt โดดเด่น และแตกต่างๆ จาก  Framework อื่น นั่นคือ Signals & Slots Mechanism ในบทความสั้นนี้ ไม่ได้กล่าวถึงพื้นฐานของ Signals & Slots แต่จะยกตัวอย่างการใช้ความสามารถของ  Signals & Slots gเพื่อให้ Thread ต่างๆ ส่งข้อมูลมาให้ GUI ได้โดยไม่มีปัญหา ในตัวอย่างนี้ไม่ได้สมบูรณ์มากนักในมุมมองของ Multi-threading programming ว่าด้วยการเข้าถึง Shared resource เพราะไม่ได้มีการใช้ฟังก์ชั่นในกลุ่ม Thread synchronization อย่างไรก็ตาม การันตีได้ว่าโปรแกรมนี้จะไม่มีการ crash เพราะ Signals & Slots มีการจัดการส่วนนี้ให้อยู่เบื้องหลังอยู่แล้ว

ในตัวอย่างนี้จะให้ Thread แต่ละ Thread วนลูป ส่ง Id ของตัวเอง และ Loop index มาแสดงผลใน textEdit ซึ่งอยู่ใน Main-thread การทำงานในลูปแต่ละลูปของแต่ละ Thread จะมีการ sleep เพื่อให้เห็นพฤติกรรมของแต่ละ Thread ได้ง่ายขึ้น ผลสุดท้ายของโปรแกรมเป็นตามรูป




ในที่นี้มี Thread จำนวน 2 Thread ทำงานอยู่เบื้องหลัง (เรื่อมทำงานเพื่อคลิกปุ่ม Start) คือ Thread สีแดงและ Thread สีน้ำเงิน ทั้ง 2 Thread ส่ง Id และ Loop index ของตัวเองมายัง textEdit ตัวเดียวกัน



ในตัวอย่างนี้โปรแกรมพัฒนาและทดสอบการทำงานบน Ubuntu อย่างไรก็ตามเนื่องจาก Qt เป็น Cross-Platform โปรแกมที่เห็นสามารถทำงานได้ในทุก Platform
เริ่มจากสร้าง Project ใหม่ ในที่นี้คือ “Qt Widgets Application” แบบ "Dialog" และทำการวาง textEdit และ pushButton ตามรูป



dialog.h
Code: (c)
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include "worker.h"

namespace Ui {
    class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT
public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();
    Worker *worker1, *worker2;
private slots:
    void start_slot();
public slots:
    void update_slot(const QString str, const QColor col);
private:
    Ui::Dialog *ui;
};
#endif // DIALOG_H




dialog.cpp
Code: (c)
#include "dialog.h"
#include "ui_dialog.h"
#include "worker.h"

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

    worker1 = new Worker(this, Qt::red,  10000);
    worker2 = new Worker(this, Qt::blue, 30000);

    connect( worker1, SIGNAL(finished_signal()),
             worker1, SLOT(deleteLater()) );
    connect( worker2, SIGNAL(finished_signal()),
             worker2, SLOT(deleteLater()) );

    connect(worker1,
                SIGNAL(update_signal(const QString, const QColor)),
                SLOT(update_slot(const QString, const QColor)) );

    connect(worker2,
                SIGNAL(update_signal(const QString, const QColor)),
                SLOT(update_slot(const QString, const QColor)) );
    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(start_slot()));
}

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

void Dialog::start_slot()
{
    ui->textEdit->clear();
    worker1->start();
    worker2->start();
}

void Dialog::update_slot(const QString str, const QColor col)
{
    ui->textEdit->setTextColor(col);
    ui->textEdit->append(str);

    QTextCursor cur = ui->textEdit->textCursor();
    cur.movePosition(QTextCursor::End);
    ui->textEdit->setTextCursor(cur);
}




ทำการเพิ่ม class ใหม่ ในที่นี้คือ "worker"

worker.h
Code: (c)
#ifndef WORKER_H
#define WORKER_H
#include <QThread>
#include <QColor>
#include <QMessageBox>
class Worker : public QThread
{
    Q_OBJECT
public:
    Worker(QObject * parent, QColor col, int us);
    ~Worker();
    void run();

    QColor textColor;
    int sleep_us;
signals:
    void update_signal(const QString str, const QColor col);
    void finished_signal();
};
#endif // WORKER_H


worker.cpp
Code: (c)
#include "worker.h"

Worker::Worker(QObject * parent, QColor col, int us)
{
    (void)parent;
    textColor = col;
    sleep_us = us;
}

Worker::~Worker()
{
    QMessageBox::information(NULL, "Information",
                             "Destructor is called", QMessageBox::Ok);
}

void Worker::run()
{
    QString str;
    for(int i=0; i<10; i++){
        str.sprintf("Thread Id:=%.6X : %.4d",
                    (int)QThread::currentThreadId(), i);
        emit update_signal(str, this->textColor);
        this->usleep(this->sleep_us);
    }
    emit finished_signal();
}



ไฟล์ต่างๆ ใน Project


รายละเอียดของ code ไม่ขออธิบายนะครับ เพราะไม่ได้มีอะไรซับซ้อนในโลกของ Qt หาก ไม่เข้าใจส่วนไหน ถามได้เลยครับ :)
บันทึกการเข้า

By SDW: Do No Wrong Is Do Nothing
          If you want to increase your success rate, double your failure rate
หน้า: [1]   ขึ้นบน
  พิมพ์  
 
กระโดดไป: