بتـــــاريخ : 2/26/2011 12:18:49 AM
الفــــــــئة
  • الحـــــــــــاسب
  • التعليقات المشاهدات التقييمات
    0 1553 0


    دوال المستوى العالي لبرمجة تطبيقات متعددة المسالك

    الناقل : elmasry | العمر :42 | الكاتب الأصلى : مصفوفة | المصدر : www.arabteam2000-forum.com

    كلمات مفتاحية  :

    السلام عليكم
    بسم الله الرحمن الرحيم
    دوال المستوى العالي لبرمجة تطبيقات متعددة المسالك :-
    يمكنك الآن نسيان جميع ماسبق عن تعدد المسالك , إذا كنت قد مللت من الوراثة من فئات وبرمجة سطور كثيرة لتحصل على تطبيق متعددة المسالك فإنك بإمكانك القاء هذه المعاناة الى الماضي والبدء مع دوال المستوى العالي لبرمجة تطبيقات متعددة المسالك .
    فضاء الأسماء QtConcurrent:-
    توفر لك دوال المستوى العالي امكانية عمل برامج متعددة المسالك بدون إستخدام فئات ودوال وتقنيات ذات مستوى منخفض مثل الإقصاء المتبادل أو الإقفال للقراءة أو الكتابة او حالة الغنتظار أو حتى semaphore .
    التطبيقات المكتوبة بواسطة QtConcurrent تقوم بتعديل عدد مسالكها وفقا للمتوفر في المعالجات الأساسية .
    وأبسط هذه الدوال هي QtConcurrent::run() التي تستقبل مؤشر لدالة تقوم بتنفيذها في مسلك مختلف وسوف يكون مدار بواسطة QthreadPool الرئيسي (راجع المقال السابق) أنظر المثال :-

    1.      #include <QtGui>
    2.      void myThread(){
    3.      for(int i=0;i<=10;i++)
    4.      qDebug()<<"1";
    5.      }
    6.      int main(int argc, char *argv[])
    7.      {
    8.      QApplication a(argc, argv);
    9.      QtConcurrent::run(myThread);
    10.     QMessageBox::information(&w,"multi-threading","run");
    11.     return a.exec();
    12.     }

    وسوف تكون المخرجات
    1111111111
    الدالة QtConcurrent::blockingMap() سوف يتم إستدعاء الدالة مرة واحدة لكل عنصر في الحاوية وكل على مسلكه الخاص انظر المثال

    1.      #include <QtGui>
    2.      void print(QString str)
    3.      {
    4.      qDebug() <<str;
    5.      }
    6.      int main(int argc, char *argv[])
    7.      {
    8.      QApplication app(argc, argv);
    9.      QStringListstr;
    10.     str<<"Qt-ar"<<"msfofa"<<"sudanix"<<
    11.     "arabTeam"<<"mohammmed alabdaly";
    12.     QtConcurrent::blockingMap(str,print);
    13.     return 0;
    14.     }

    وسوف تكون مخرجات البرنامج
    "Qt-ar"
    "sudanix"
    "msfofa"
    "arabTeam"
    "mohammmed alabdaly"
    وبما ان المخرجات من عدة مسالك فالترتيب سوف يتغير في كل تجربة للبرنامج .
    لاحظ اشتراك المصدر في حاوية واحدة معروفة بأن دوالها جميعا reentrant وأيضا الدالة التي قمت بصنعها انت تقع تحت هذا الإطار ولكن دوال المستوى العالي جميعها thread-safe تقوم بهذا تلقائيا وتريحك من عناء كتابة أسطر الشفرات .
    ملاحظة: هذه الوظيفة سوف تكون مقفلة حتى يتم معالجة جميع عناصر الحاوية .

    الفئين QFuture و QFutureWatcher
    الأول لإستقبال نتائج العمليات والثاني يوفر لك اشارات لمراقبة نتائج العمليات .
    أنظر هذا المثال

    1.      #include <QtGui>
    2.      QString myThread(){
    3.      return "www.qt-ar.com";
    4.      }
    5.      int main(int argc, char *argv[])
    6.      {
    7.      QApplication a(argc, argv);
    8.      QFuture<QString>future=QtConcurrent::run(myThread);
    9.      future.waitForFinished();
    10.     qDebug()<<future.result();
    11.     return 0;
    12.     }
    هذا المثال يعتمد على الدالة run التي تحدثنا عنها مسبقا .
    في الأسطر من 2-4 قمنا بإنشاء الدالة التي سوف نستخدمهافي المسلك 8-10 قمنا بتنفيذ الدالة في مسلك منفرد وصرحنا عن المتغير future الذي سوف يستقبل ناتج العملية ثم استدعينا الدالة waitForFinished الذي أخبر المسلك الرئيسي بأن ينتظر حتى ينتهي المتغير future من إستقبال جميع النتائج من المسالك لنطبعه بعد ذلك بإستدعاء الداة result .
    في المثال السابق لقد أستخدمنا الدالة waitForFinished(); حتى نظمن حين طلبنا للنتائج تكون متوفرة بالكامل ولكن في الحقيقة هي عملية ليست ذات جدوى في البرامج المعقدة فلذلك من الأفضل أن تستخدم الفئة QfutureWatcher لكي تستقبل إشارات في حال تم الإنتهاء من مخرجات معالج واحد أو جميع المعالجات أو .... وقبل كل هذا يجب عليك إضافة Qfuture الى QfutureWatcher بإستدعاء الدالة setFuture .
    بعض أهم الإشارات :-
    ترسل الإشارة حينتوفر نتيجة جديدة للقراءة .resultReadyAt()
    ترسل إشارة حين توفر نتائج جديدة للقراءة .resultsReadyAt()
    حين الإنتهاء من مراقبة النتائج .finished()
    started() أثناء البدء بمراقبة النتائج أي عند استخدامك الدالة setFuture.
    عند الغاء عملية المراقبة .canceled()
    resumed() عند إكمال العملية بعد إيقافها .
    progressValueChanged() أثناء الحصول على نتيجة فإنه يخبرك بمقدار التقدم الذي حصل و التي تعبر عن عدد النتائج التي أستطاع المراقب معرفتها حيث يكون اعلى قيمة عندما يتم إستقبال جميع النتائج .
    progressRangeChanged() ترسل إشارة في حال حصول تغير في مدى النتائج التي سوف يتم إستقبالها .

    دوال أخرى في فضاء الأسماء QtConcurrent
    QtConcurrent::map() وهي شبيهة للدالة blockingMap حيث أنها تطلب دال تعيد القيمة void وحاوية ولكنها تعيد QFuture<void> .
    أنظر المثال (منقول)

    1.      #include <QtGui>
    2.      using namespace QtConcurrent;
    3.      const int iterations = 20;
    4.      void spin(int &iteration)
    5.      {
    6.      const int work = 1000 * 1000 * 40;
    7.      volatile int v = 0;
    8.      for (int j = 0; j < work; ++j)
    9.      ++v;
    10.     qDebug() << "iteration" << iteration << "in thread" << QThread::currentThreadId();
    11.     }
    12.     int main(int argc, char **argv)
    13.     {
    14.     QApplication app(argc, argv);
    15.     QVector<int> vector;
    16.     for (int i = 0; i < iterations; ++i)
    17.     vector.append(i);
    18.     QProgressDialog dialog;
    19.     dialog.setLabelText(QString("Progressing using %1 thread(s)...").arg(QThread::idealThreadCount()));
    20.     QFutureWatcher<void> futureWatcher;
    21.     QObject::connect(&futureWatcher, SIGNAL(finished()), &dialog, SLOT(reset()));
    22.     QObject::connect(&dialog, SIGNAL(canceled()), &futureWatcher, SLOT(cancel()));
    23.     QObject::connect(&futureWatcher, SIGNAL(progressRangeChanged(int, int)), &dialog, SLOT(setRange(int, int)));
    24.     QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &dialog, SLOT(setValue(int)));
    25.     futureWatcher.setFuture(QtConcurrent::map(vector, spin));
    26.     dialog.exec();
    27.     futureWatcher.waitForFinished();
    28.     }

    في الأسطر 4-11 قمنا بتعريف الدالة التي سوف نستخدمها في المسالك
    وفي الأسطر من 15-19 قمنا بإنشاء حاوية وأضفنا لها القيم من 0 الى 19 ومن ثم أنشأنا progress dialog
    20-24 قمنا بإنشاء future watcher لنقوم بالربط بين إشارات الأخير ومستقبلات progress dialog .
    25-28 قمنا بإستخدام الدالة map التي سوف تقوم بإنشاء المسالك بشرط أن نعطيها دالة ترجع void و الحاوية التي تستقبل منها القيم ثم يبدأ بالتنفيذ وينتر حتى ينتهي من معالجة جميع المسالك وأخذ القيم منها.
    لاحظ أن ال progress par سوف يمتلئ بنسبة 100% عندما تنتهي الدالة waitForFinished(); من عملها .

    QtConcurrent::mapped() شبيه للدالة map ولكنك سوف تتعامل مع دوال لايشترط فيها نوع المخرجات بعكس map والتي تشترط أن يكون void أي أن مخرجات mapped سوف تكون QFuture<T> .

    دوال التنقيح للحاويات :-
    QtConcurrent::filter() و QtConcurrent::filtered()
    ودوالها يجب أن تعيد القيمة true او false حيث القيمة false تعني أن هذا العنصر في الحاوية يجب أن لايستقبلها Qfuture والفرق بين filter و filtered أن الأول يعيد Qfuture<void> والثاني يعيد Qfuture<T> وجميعها تستقبل القيم التي سوف تعيد true مع الدالة .
    يمكن إختصارها في السطرين التاليين

    1.      // keep only images with an alpha channel
    2.      QList<QImage> images = ...;
    3.      QFuture<void> alphaImages = QtConcurrent::filter(strings, &QImage::hasAlphaChannel);
    4.      // keep only gray scale images
    5.      QList<QImage> images = ...;
    6.      QFuture<QImage> grayscaleImages = QtConcurrent::filtered(images, &QImage::isGrayscale);
    بالإضافة الى ذلك يوجد هناك دوال أخرى راجع ملف QtAssistant ويمكنك مطالعة الأمثلة أيضا لمزيد من طرق التعامل .

    كلمات مفتاحية  :

    تعليقات الزوار ()