multithreading - مثال بسيط للخيوط في C++




(7)

يمكن للشخص نشر مثال بسيط على بدء اثنين (المواضيع الموجه) في C ++.

أنا أبحث عن كائنات مؤشر الترابط C ++ الفعلية التي يمكنني توسيع أساليب تشغيل على (أو شيء مماثل) بدلاً من استدعاء مكتبة مؤشر ترابط C- نمط.

تحديث - لقد استبعدت أي طلبات خاصة بنظام التشغيل على أمل أن يرد أي شخص أجاب بواسطة مكتبات الأنظمة الأساسية لاستخدامها. أنا فقط أقوم بهذا الوضوح الآن.


Answers

قم بإنشاء دالة تريد أن ينفذها مؤشر الترابط. سوف أعرض مع مثال تافه:

void task1(std::string msg)
{
    std::cout << "task1 says: " << msg;
}

الآن إنشاء كائن thread الذي سيستدعي الدالة أعلاه في النهاية مثل:

std::thread t1(task1, "Hello");

(تحتاج إلى #include <thread> للوصول إلى فئة std::thread )

كما ترى ، فإن حجج المنشئ هي الدالة التي سينفذها مؤشر الترابط ، متبوعة بمعلمات الدالة.

وأخيرًا ، انضم إلى الموضوع الرئيسي للتنفيذ مثل:

t1.join(); 

(يعني الانضمام أن مؤشر الترابط الذي استدعى مؤشر الترابط الجديد سينتظر أن ينتهي مؤشر الترابط الجديد من التنفيذ ، قبل أن يتابع التنفيذ الخاص به).

الرمز

#include <string>
#include <iostream>
#include <thread>

using namespace std;

// The function we want to execute on the new thread.
void task1(string msg)
{
    cout << "task1 says: " << msg;
}

int main()
{
    // Constructs the new thread and runs it. Does not block execution.
    thread t1(task1, "Hello");

    // Makes the main thread wait for the new thread to finish execution, therefore blocks its own execution.
    t1.join();
}

مزيد من المعلومات حول موضوع std :: هنا

  • على GCC ، ترجمة مع -std=c++0x -pthread .
  • هذا يجب أن يعمل لأي نظام تشغيل ، منح المجمع الخاص بك يدعم هذه الميزة (C ++ 11).

حسنا ، من الناحية الفنية أي كائن من هذا القبيل سوف ينتهي بناؤها عبر مكتبة مؤشر ترابط C- نمط لأن C ++ فقط حددت فقط نموذج std::thread في c + + + + ، الذي تم فقط مسمر ولم يتم تنفيذه بعد. المشكلة هي نظامية إلى حد ما ، فنموذج ذاكرة c ++ الموجود ليس صارماً بما يكفي للسماح بدلالات محددة جيداً لكل الحالات "التي تحدث قبل". كتب هانز بوهم ورقة حول هذا الموضوع منذ فترة طويلة ، وكان له دور فعال في التوصل إلى معيار c ++ 0x في هذا الموضوع.

http://www.hpl.hp.com/techreports/2004/HPL-2004-209.html

وقال أن هناك عدة مكتبات C ++ موضوع عبر منصة التي تعمل على ما يرام في الممارسة العملية. تحتوي كتل الإنشاء مؤشر ترابط Intel على كائن مؤشر ترابط tbb :: يقترب بشكل كبير c ++ 0x القياسي و Boost يحتوي على مكتبة boost :: thread يفعل نفس.

http://www.threadingbuildingblocks.org/

http://www.boost.org/doc/libs/1_37_0/doc/html/thread.html

باستخدام boost :: thread يمكنك الحصول على شيء من هذا القبيل:

#include <boost/thread.hpp>

void task1() { 
    // do stuff
}

void task2() { 
    // do stuff
}

int main (int argc, char ** argv) {
    using namespace boost; 
    thread thread_1 = thread(task1);
    thread thread_2 = thread(task2);

    // do other stuff
    thread_2.join();
    thread_1.join();
    return 0;
}

هنا طريقة أكثر قوة لإنشاء عدد عشوائي من مؤشرات الترابط (في C ++ 11 أو أحدث):

#include <thread>
#include <iostream>
using namespace std;

void doSomething(int id) {
    cout << "Thread id = " << id;
}

/**
 * Spawns n threads
 */
void spawnThreads(int n)
{
    thread threads[n];
    // spawn n threads:
    for (int i = 0; i < n; i++) {
        threads[i] = thread(doSomething, i + 1);
    }

    for (auto& th : threads) {
        th.join();
    }
}

هناك أيضا مكتبة POSIX لأنظمة التشغيل POSIX. Check التوافق

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <iostream>

void *task(void *argument){
      char* msg;
      msg = (char*)argument;
      std::cout<<msg<<std::endl;
}

int main(){
    pthread_t thread1, thread2;
    int i1,i2;
    i1 = pthread_create( &thread1, NULL, task, (void*) "thread 1");
    i2 = pthread_create( &thread2, NULL, task, (void*) "thread 2");

    pthread_join(thread1,NULL);
    pthread_join(thread2,NULL);
    return 0;

}

ترجمة مع -lpthread

http://en.wikipedia.org/wiki/POSIX_Threads


عند البحث عن مثال لفئة C ++ تستدعي إحدى طريقتها الخاصة بها في سلسلة محادثات جديدة ، يظهر هذا السؤال ، لكننا لم نتمكن من استخدام أي من هذه الإجابات بهذه الطريقة. إليك مثال يفعل ذلك:

Class.h

class DataManager
{
public:
    bool hasData;
    void getData();
    bool dataAvailable();
};

Class.cpp

#include "DataManager.h"

void DataManager::getData()
{
    // perform background data munging
    hasData = true;
    // be sure to notify on the main thread
}

bool DataManager::dataAvailable()
{
    if (hasData)
    {
        return true;
    }
    else
    {
        std::thread t(&DataManager::getData, this);
        t.detach(); // as opposed to .join, which runs on the current thread
    }
}

لاحظ أن هذا المثال لا يدخل في كائن المزامنة أو القفل.


ما لم يكن أحدهم يريد وظيفة منفصلة في أسماء الأسماء العالمية ، يمكننا استخدام وظائف lambda لإنشاء سلاسل رسائل.

واحدة من المزايا الرئيسية لإنشاء موضوع باستخدام لامبدا هو أننا لسنا بحاجة إلى تمرير المعلمات المحلية كقائمة حجة. يمكننا استخدام قائمة الالتقاط لنفسه وسيقوم عقار الإغلاق الخاص بـ lambda بالاعتناء بدورة الحياة.

هنا رمز عينة

int main() {
    int localVariable = 100;

    thread th { [=](){
        cout<<"The Value of local variable => "<<localVariable<<endl;
    }}

    th.join();

    return 0;
}

حتى الآن ، وجدت lambdas C ++ أن أفضل طريقة لإنشاء المواضيع خاصة لوظائف مؤشر ترابط أبسط


بالنسبة إلى .NET 2.0 ، إليك جزءًا رائعًا من التعليمات البرمجية التي كتبتها تمامًا كما تريد ، وتعمل مع أي خاصية على جهاز Control :

private delegate void SetControlPropertyThreadSafeDelegate(
    Control control, 
    string propertyName, 
    object propertyValue);

public static void SetControlPropertyThreadSafe(
    Control control, 
    string propertyName, 
    object propertyValue)
{
  if (control.InvokeRequired)
  {
    control.Invoke(new SetControlPropertyThreadSafeDelegate               
    (SetControlPropertyThreadSafe), 
    new object[] { control, propertyName, propertyValue });
  }
  else
  {
    control.GetType().InvokeMember(
        propertyName, 
        BindingFlags.SetProperty, 
        null, 
        control, 
        new object[] { propertyValue });
  }
}

يطلق عليه مثل هذا:

// thread-safe equivalent of
// myLabel.Text = status;
SetControlPropertyThreadSafe(myLabel, "Text", status);

إذا كنت تستخدم .NET 3.0 أو أعلى ، فيمكنك إعادة كتابة الطريقة السابقة كأسلوب ملحق لفئة Control ، مما يؤدي إلى تبسيط الاستدعاء إلى:

myLabel.SetPropertyThreadSafe("Text", status);

التحديث 05/10/2010:

بالنسبة إلى .NET 3.0 ، يجب استخدام هذا الرمز:

private delegate void SetPropertyThreadSafeDelegate<TResult>(
    Control @this, 
    Expression<Func<TResult>> property, 
    TResult value);

public static void SetPropertyThreadSafe<TResult>(
    this Control @this, 
    Expression<Func<TResult>> property, 
    TResult value)
{
  var propertyInfo = (property.Body as MemberExpression).Member 
      as PropertyInfo;

  if (propertyInfo == null ||
      [email protected]().IsSubclassOf(propertyInfo.ReflectedType) ||
      @this.GetType().GetProperty(
          propertyInfo.Name, 
          propertyInfo.PropertyType) == null)
  {
    throw new ArgumentException("The lambda expression 'property' must reference a valid property on this Control.");
  }

  if (@this.InvokeRequired)
  {
      @this.Invoke(new SetPropertyThreadSafeDelegate<TResult> 
      (SetPropertyThreadSafe), 
      new object[] { @this, property, value });
  }
  else
  {
      @this.GetType().InvokeMember(
          propertyInfo.Name, 
          BindingFlags.SetProperty, 
          null, 
          @this, 
          new object[] { value });
  }
}

الذي يستخدم تعبيرات LINQ و lambda للسماح ببناء أكثر نظافة وبساطة وأمانًا:

myLabel.SetPropertyThreadSafe(() => myLabel.Text, status); // status has to be a string or this will fail to compile

ليس فقط اسم الخاصية محدد الآن في وقت التحويل البرمجي ، نوع الخاصية كذلك ، لذا من المستحيل (على سبيل المثال) تعيين قيمة سلسلة لخاصية منطقية ، وبالتالي تسبب استثناء وقت التشغيل.

لسوء الحظ هذا لا يمنع أي شخص من القيام بأشياء غبية مثل تمرير خاصية وقيمة Control أخرى ، لذلك سوف يجمع ما يلي بسعادة:

myLabel.SetPropertyThreadSafe(() => aForm.ShowIcon, false);

وبالتالي أضفت عمليات التحقق من وقت التشغيل للتأكد من أن الخاصية التي تم تمريرها تنتمي بالفعل إلى Control الذي يتم استدعاء الأسلوب عليه. ليس مثاليا ، ولكن لا يزال أفضل بكثير من إصدار .NET 2.0.

إذا كان لدى أي شخص أي اقتراحات أخرى حول كيفية تحسين هذا الرمز لضمان سلامة وقت التحويل ، يرجى التعليق!





c++ multithreading