رفتن به مطلب
مرجع رسمی سی‌پلاس‌پلاس ایران
  • 0
قاسم رمضانی منش

مشکل دسترسی به متغیر‌ در نخ (Thread) ها


سوال

ارسال شده در (ویرایش شده)

با سلام.

در حال یادگیرQt و Thread ها بودم که به مشکل دسترسی به متغیر در Thread بر خوردم.

کلاس زیر از QThread مشتق شده است :

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>
#include <QWidget>
#include <QThread>
#include <QMutex>

class MyThread : public QThread
{
    Q_OBJECT
  public:
    explicit MyThread(QObject *parent = nullptr);
    void run() override;
    bool Stop;

  signals:
    void NumberChanged(int);
};

#endif // MYTHREAD_H



#include "mythread.h"

MyThread::MyThread(QObject *parent) : QThread (parent)
{

}

void MyThread::run()
{
  for(int i=0; i<100000000 ; ++i){
      QMutex mutex;
       mutex.lock();
      if (this->Stop) break;
      mutex.unlock();

      emit NumberChanged(i);
      this->msleep(100);
    }
}

 

داخل فرم خودم دو QPushBotton و یک QLabel دارم. که یکی از دکمه‌ها (QPushButton) وظیفه اجرای یک QThread  را دارد و یکی دیگه باعث متوقف کردن کار QThread  ایجاد شده :

#include "dialog.h"
#include "ui_dialog.h"

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

  mThread = new MyThread(this);
  connect(mThread,SIGNAL(NumberChanged(int)),this,SLOT(onNumberChanged (int)));

}

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

void Dialog::onNumberChanged(int Number){
  ui->label->setText(QString::number(Number));
}

void Dialog::on_pushButton_clicked(){
  mThread->start();
}

void Dialog::on_pushButton_2_clicked(){
  mThread->Stop = false;
}

 

در کد بالا زمانی‌که on_pushButton_clicked فراخوانی شد. QThread را اجرا میکند. و در مقابل زمانی‌که on_pushButton_2_clicked فراخوانی شد. متغیر bool MyThread::Stop را برابر مقدار false میگذارد که باعث از بین رفتن عملیات QThread ایجاد شده میشود. اما در اصل هیچ تفاوتی ایجاد نمیکند ؟ و زمان بستن برنامه با خطای لاگ زیر برخورد میکنم :

21:39:20: Starting /tmp/untitled/build-untitled-Desktop_Clang_7_0_0-Debug/untitled...
QThread: Destroyed while thread is still running
21:39:32: The program has unexpectedly finished.
21:39:32: The process was ended forcefully.
21:39:32: /tmp/untitled/build-untitled-Desktop_Clang_7_0_0-Debug/untitled crashed.

کجای کار اشتباه شده است ؟ 

 

ویرایش شده در توسط قاسم رمضانی منش

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر

5 پاسخ به این سوال تا کنون داده شده است

پست های پیشنهاد شده

  • 1
ارسال شده در (ویرایش شده)
در در 28 آذر 1397 در 21:47، قاسم رمضانی منش گفته است :

for(int i=0; i<100000000 ; ++i){

QMutex mutex;

mutex.lock();

if (this->Stop) break;

mutex.unlock();

emit NumberChanged(i);

this->msleep(100);

}

 

این که درست نیست توی هر حلقه یک mutex درست کردی باید یدونه باشه تا وقتی قفل میکنی دسترسی به منبع رو قبول کنه. ببر بیرون تعریف کن و همون یدونه رو باید lock و unlock کنی.

یه نگاهی به مثال خود رفرنس بنداز :

std::mutex - cppreference.com

موفق باشی.

ویرایش شده در توسط کامبیز اسدزاده
املاء و نگارش

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0

سلام 

متن دکمهٔ اولتون متغیر stop رو flase قرار بدید و در دکمه ی دومتون برابر با true چون به طور پیش فرض true هستش! و شرط هم باید true باشه که همین موضوع هم باعث می شه از حلقه خارج بشه.

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0
ارسال شده در (ویرایش شده)

درست متوجه منظورتون نشدم ! ولی :

void Dialog::on_pushButton_2_clicked(){
  mThread->Stop = false;
}

این اسلات (slot) وقتی صدا زده میشه خب باید مقدار متغیر MyThread::Stop رو برابر false  قرار بده دیگه ! درسته ؟

و طبق دستوراتی که داخل تابع void MyThread::run نوشته شده : درصورتی‌که این متغیر مقدارش false باشه باید حلقه شکسته بشه و دیگه چیزی emit نکنه.

و وقتی ما این اسلات را فراخوانی میکنیم. اتفاقی نمی‌افته و باز حلقه به کار خودش ادامه میده.

ویرایش شده در توسط قاسم رمضانی منش

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0
در 12 ساعت قبل، قاسم رمضانی منش گفته است :

درست متوجه منظورتون نشدم ! ولی :



 
 
void Dialog::on_pushButton_2_clicked(){
 
mThread->Stop = false;
 
}

این اسلات (slot) وقتی صدا زده میشه خب باید مقدار متغیر MyThread::Stop رو برابر false  قرار بده دیگه ! درسته ؟

و طبق دستوراتی که داخل تابع void MyThread::run نوشته شده : درصورتی‌که این متغیر مقدارش false باشه باید حلقه شکسته بشه و دیگه چیزی emit نکنه.

و وقتی ما این اسلات را فراخوانی میکنیم. اتفاقی نمی‌افته و باز حلقه به کار خودش ادامه میده.

ببیند متغیر Stop رو تعریف کردید اما مقدار true یا false رو بهش ندادید! پس بطور پیش فرض true قرار می گیره، همین موضوع باعث می شه وقتی Thread  رو start کنید تابع run اجرا می شه،وبه شرط که رسید شرط درست می شه و break  می کنه یعنی همون اول که start بشه حلقه شکسته می شه چون متغیر Stop پیش فرض true هستش پس اول توی رویداد کلیک دکمه ی اولتون متغیر Stop  رو برابر با false کنید تا وقتی تابع run اجرا شد شرط false بشه و به emit کردن ادامه بده، و توی رویداد کلیک دومتون برابر با true قرار بدید.

با علامت نقیض(!) می تونید برعکس کنید یعنی توی دکمه ی اول همون treu باشه توی دکمه ی دوم false.

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
  • 0

دو تا مشکل داشتید:

۱- وقتی که روی دکمه stop کلیک می کنید به شمردن ادامه میده:

برای من که چنین اتفاقی نیفتاد، با کامپایلرهای دیگه امتحان کنید، کدها رو به صورت زیر تغییر بدید ببینید چی می شه:

#include "mythread.h"
#include <QCoreApplication>

MyThread::MyThread(QObject *parent) : QThread (parent)
{
    stop = false;
}

void MyThread::run()
{
    for(quint32 i = 0; i < 100000000; i++) {
        if (stop) break;
        emit numberChanged(i);
        this->msleep(100);
        QCoreApplication::processEvents();
    }
    exec();
}

۲- به هنگام خروج از برنامه خطا میداد:

تغییرات بالا رو اعمال کنید و  هنگام تعریف کلاس به صورت زیر بنویسید:

mThread = new MyThread(this);
connect(mThread, &MyThread::finished, mThread, &QObject::deleteLater);
connect(mThread, &MyThread::numberChanged, this, &MainWindow::updateUi);

و تخریبگر فرم رو هم به صورت زیر تغییر دهید:

MainWindow::~MainWindow()
{
    mThread->stop = true;
    mThread->quit();
    mThread->wait();
    delete ui;
}

 

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر

به گفتگو ملحق شوید

شما همین الآن می‌توانید مطلبی را ارسال و بعداً ثبت‌نام کنید. اگر حساب کاربری دارید، و با حساب کاربری خود مطلب ارسال کنید.
نکته: مطلب شما قبل از انتشار نیاز به بازبینی توسط میانجی‌گر‌ها دارد.

مهمان
پاسخ به این سوال ...

×   شما در حال چسباندن محتوایی با قالب بندی هستید.   حذف قالب بندی

  تنها استفاده از ۷۵ اموجی مجاز می باشد.

×   لینک شما به صورت اتوماتیک جای گذاری شد.   نمایش به عنوان یک لینک به جای

×   محتوای قبلی شما بازگردانی شد.   پاک کردن محتوای ویرایشگر

×   شما مستقیما نمی توانید تصویر خود را قرار دهید. یا آن را اینجا بارگذاری کنید یا از یک URL قرار دهید.


  • کاربران آنلاین در این صفحه   0 کاربر

    هیچ کاربر عضوی،در حال مشاهده این صفحه نیست.

×
×
  • جدید...