मैं वीएस2015 का उपयोग कर क्यूटी के माध्यम से अपने इंटरफेस को महसूस करने वाली सी ++ लाइब्रेरी विकसित कर रहा हूं। लाइब्रेरी की तरफ, 3 थ्रेड्स को बूस्ट करें लगातार 3 फोल्डर से इमेज लोड करते हैं। मैं इन छवियों को 3 अलग-अलग QLabel (या समकक्ष QWidgets) में प्रदर्शित करने का प्रयास कर रहा हूं, इसलिए थ्रेड बॉडी में यह कार्यक्षमता शामिल है, विशेष रूप से setPixmap पद्धति का उपयोग करके। हालांकि फ़ंक्शन को कॉल बूस्ट म्यूटेक्स द्वारा संरक्षित है, मुझे शायद थ्रेड सिंक्रनाइज़ेशन के कारण अपवाद मिले हैं। एक समाधान की तलाश में, मुझे पहले से ही पता था कि QPixmap विजेट "थ्रेड-सुरक्षित" (गैर-पुनर्प्रवेशकर्ता) नहीं है। मैंने QGraphicsView का उपयोग करने का भी प्रयास किया लेकिन यह बदले में QPixmap पर निर्भर करता है, इस प्रकार मुझे एक ही समस्या का सामना करना पड़ा। तो मेरा प्रश्न है: क्या QPixmap का विकल्प Qt में छवियों को थ्रेड-सुरक्षित में प्रदर्शित करने के लिए मौजूद है? तौर - तरीका?

0
Fabio 23 नवम्बर 2017, 16:41

2 जवाब

सबसे बढ़िया उत्तर

मैंने सिग्नल/स्लॉट का उपयोग करके हल किया: "गैर-जीयूआई" थ्रेड छवियों को प्रदर्शित करने के बजाय सिग्नल उत्सर्जित करता है और तथाकथित स्लॉट क्यूएलएबल को जीयूआई थ्रेड के अंदर पेंट करता है!

0
Fabio 27 नवम्बर 2017, 11:21

मैं GUI प्रोग्रामिंग में मल्टी-थ्रेडिंग न करने की सलाह दूंगा। हालाँकि, Qt सामान्य रूप से बहु-थ्रेडिंग समर्थन प्रदान करता है, IMHO, विजेट इसके लिए अच्छी तरह से तैयार नहीं हैं।

इस प्रकार, छवि लोडर प्राप्त करने के लिए जो अलग-अलग धागे में एक साथ चलते हैं, मैं निम्नलिखित अवधारणा का सुझाव दूंगा:

प्रत्येक थ्रेडेड इमेज लोडर एक निजी बफर को फीड करता है। GUI समय-समय पर (QTimer का उपयोग करके) इन बफ़र्स का निरीक्षण करता है और इसके QPixmap को अपडेट करता है। चूंकि सम्मान से बफर तक पहुंच संभव होनी चाहिए। छवि लोडर थ्रेड के साथ-साथ जीयूआई थ्रेड को निश्चित रूप से म्यूटेक्स संरक्षित किया जाना है।

मेरा नमूना कोड testLoadImageMT.cc:

#include <atomic>
#include <chrono>
#include <mutex>
#include <thread>
#include <QtWidgets>

// manually added types (normally provided by glib)
typedef unsigned guint;
typedef unsigned char guint8;

// the fluffy-cat image sample
struct Image {
  guint      width;
  guint      height;
  guint      bytes_per_pixel; /* 3:RGB, 4:RGBA */
  guint8     pixel_data[1];
};
extern "C" const Image fluffyCat;

class ImageLoader {
  private:
    const Image &_img;
    std::atomic<bool> _exit;
    std::mutex _lock;
    QImage _qImg;
    std::thread _thread;

  public: // main thread API

    ImageLoader(const Image &img = fluffyCat):
      _img(img),
      _qImg(img.width, img.height, QImage::Format_RGB888),
      _exit(false), _thread(&ImageLoader::loadImage, std::ref(*this))
    { }

    ~ImageLoader()
    {
      _exit = true;
      _thread.join();
    }

    ImageLoader(const ImageLoader&) = delete;

    void applyImage(QLabel &qLblImg)
    {
      std::lock_guard<std::mutex> lock(_lock);
      qLblImg.setPixmap(QPixmap::fromImage(_qImg));
    }

  private: // thread private

    void loadImage()
    {
      for (;;) {
        { std::lock_guard<std::mutex> lock(_lock);
          _qImg.fill(0);
        }
        size_t i = 0;
        for (int y = 0; y < (int)_img.height; ++y) {
          for (int x = 0; x < (int)_img.width; ++x) {
            const quint32 value
              =  _img.pixel_data[i + 2]
              | (_img.pixel_data[i + 1] << 8)
              | (_img.pixel_data[i + 0] << 16)
              | (0xff << 24);
            i += _img.bytes_per_pixel;
            { std::lock_guard<std::mutex> lock(_lock);
              _qImg.setPixel(x, y, value);
            }
            if (_exit) return; // important: make thread co-operative
          }
          std::this_thread::sleep_for(std::chrono::milliseconds(100)); // slow down CPU cooler
        }
      }
    }
};

int main(int argc, char **argv)
{
  // settings:
  enum { N = 3 }; // number of images loaded/displayed
  enum { Interval = 50 }; // update rate for GUI 50 ms -> 20 Hz (round about)
  // build appl.
  qDebug() << "Qt Version: " << QT_VERSION_STR;
  QApplication app(argc, argv);
  // build GUI
  QWidget qMainWin;
  QVBoxLayout qVBox;
  QLabel *pQLblImgs[N];
  for (int i = 0; i < N; ++i) {
    qVBox.addWidget(
      new QLabel(QString::fromUtf8("Image %1").arg(i + 1)));
    qVBox.addWidget(
      pQLblImgs[i] = new QLabel());
  }
  qMainWin.setLayout(&qVBox);
  qMainWin.show();
  // build image loaders
  ImageLoader imgLoader[N];
  // install timer
  QTimer qTimer;
  qTimer.setInterval(Interval); // ms
  QObject::connect(&qTimer, &QTimer::timeout,
    [&imgLoader, &pQLblImgs]() {
      for (int i = 0; i < N; ++i) {
        imgLoader[i].applyImage(*pQLblImgs[i]);
      }
    });
  qTimer.start();
  // exec. application
  return app.exec();
}

क्षमा करें, मैंने boost::thread के बजाय std::thread का उपयोग किया क्योंकि मुझे बाद वाले के साथ कोई अनुभव नहीं है, न ही कोई कार्यशील स्थापना। मुझे विश्वास है (उम्मीद है) मतभेद मामूली होंगे। QThread "क्यूटी नेटिव" विकल्प होता लेकिन फिर से - कोई अनुभव नहीं।

चीजों को सरल रखने के लिए, मैंने सिर्फ एक लिंक की गई बाइनरी छवि से डेटा कॉपी किया है (फ़ाइल से या कहीं और से लोड करने के बजाय)। इसलिए, इसे एक MCVE बनाने के लिए एक दूसरी फ़ाइल को संकलित और लिंक करना होगा - fluffyCat.cc:

/* GIMP RGB C-Source image dump (fluffyCat.cc) */

// manually added types (normally provided by glib)
typedef unsigned guint;
typedef unsigned char guint8;

extern "C" const struct {
  guint      width;
  guint      height;
  guint      bytes_per_pixel; /* 3:RGB, 4:RGBA */ 
  guint8     pixel_data[16 * 16 * 3 + 1];
} fluffyCat = {
  16, 16, 3,
  "x\211s\215\232\200gw`fx`at[cx^cw^fu\\itZerWn|ap~cv\204jnzedq^fr^kzfhv^Ra"
  "GRbMWdR\\jXer^qw_\311\256\226\271\253\235\275\264\252\315\277\260\304\255"
  "\231u~i\213\225\207l{fly`jx\\^nRlz_z\206nlx`t~i\221\211s\372\276\243\375"
  "\336\275\376\352\340\356\312\301\235\216\212judgwcl~f\212\226u}\206h\212"
  "\224q\231\237z\232\236{\216\225v\225\230\200\306\274\244\376\360\327\376"
  "\361\331\376\360\341\326\275\272\253\240\244{\203p\202\220xp~e{\204^\222"
  "\230n\212\217g\240\242{\234\236z\214\222r\270\271\247\360\353\340\376\370"
  "\336\376\363\334\375\357\336\310\254\262\232\223\234\\gRfrX\204\220z\212"
  "\225g\225\232j\254\255\177\252\250{\225\226u\304\302\265\374\365\351\376"
  "\375\366\376\367\341\376\361\320\374\346\324\306\241\242\237\232\235n{fj"
  "xckyfu~fUX@VZCfnT\231\231\207\374\374\371\377\372\354\376\376\374\376\376"
  "\372\376\362\332\375\340\301\341\300\264\260\253\262jvdbq\\XkVJTDNTCCG8O"
  "TE\322\321\313\377\377\375\376\376\373\376\377\376\376\376\375\376\374\362"
  "\376\360\342\344\311\306\250\244\254R_PL^HXkT<@2OP@`dP\217\220\177\374\374"
  "\370\377\377\374\376\375\371\377\377\376\376\374\360\377\367\336\376\350"
  "\316\342\303\274\246\236\245jtbXdQTdNQYGU\\KchV\317\315\302\377\376\372\377"
  "\376\367\376\373\360\377\376\367\376\366\337\376\355\312\374\331\271\323"
  "\263\251\216\214\214\\hTP^HL\\FR[LMXI^dW\355\352\342\376\375\366\377\374"
  "\360\376\374\361\376\374\361\376\356\321\374\331\264\374\330\266\330\270"
  "\260\200||Y`SLVE>K9BJ<CN?VYP\347\330\322\376\366\345\376\363\330\376\367"
  "\337\377\372\350\374\342\314\326\243\210\375\350\314\352\317\304shc^`TV`"
  "RVbT>B4IS?PTD\244\232\216\374\355\320\376\354\311\376\351\306\376\362\332"
  "\374\344\321\267\206u\375\362\337\326\274\272\\POMNBT]LNZH:<*<A*TV>OI;\242"
  "\222\207\340\304\243\375\335\262\372\336\272\376\361\334\320\241\212\374"
  "\352\322\266\233\237c\\WFH;MR>\\`F~xP\220\214[pqE\211\202\\g]=\230\214`\313"
  "\266\207\344\303\240\362\336\274\323\257\201\333\304\240\305\252\204\254"
  "\232p\216\206\\\206\203U\232\224b\234\244b\246\257m\220\232`\224\227h~\202"
  "W\206\213]\204\210W\227\227i|\177RvzNlsGrtJwtLz}N{\204RlxF",
};

मैंने विंडोज 10 (64 बिट) पर क्यूटी 5.9.2 के साथ वीएस2013 में संकलित और परीक्षण किया। यह इस तरह दिखता है:

Snapshot of testLoadImageMT

0
Scheff 25 नवम्बर 2017, 15:54