C ++ में थ्रेडिंग का सरल उदाहरण


391

क्या कोई व्यक्ति C ++ में दो (ऑब्जेक्ट ओरिएंटेड) थ्रेड शुरू करने का एक सरल उदाहरण पोस्ट कर सकता है।

मैं वास्तविक C ++ थ्रेड ऑब्जेक्ट्स की तलाश कर रहा हूं जो कि मैं सी-स्टाइल थ्रेड लाइब्रेरी को कॉल करने के विपरीत तरीके (या कुछ इसी तरह) पर चला सकता हूं।

मैंने इस उम्मीद में कोई ओएस विशिष्ट अनुरोध छोड़ दिया कि जिसने भी उत्तर दिया वह क्रॉस प्लेटफॉर्म पुस्तकालयों के साथ उपयोग करने के लिए उत्तर देगा। मैं अभी स्पष्ट कर रहा हूं।


जवाबों:


560

एक फ़ंक्शन बनाएँ जिसे आप थ्रेड निष्पादित करना चाहते हैं, जैसे:

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");

    // Do other things...

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

Std के बारे में अधिक जानकारी :: थ्रेड यहाँ

  • जीसीसी पर, के साथ संकलित करें -std=c++0x -pthread
  • यह किसी भी ऑपरेटिंग-सिस्टम के लिए काम करना चाहिए, बशर्ते आपका कंपाइलर इस (C ++ 11) फीचर को सपोर्ट करे।

4
@ Preza8 VS10 C ++ 11 में कई विशेषताओं का समर्थन नहीं करता है। VS12 और VS13 समर्थन धागा।
jodag

3
टिप्पणी में "जीसीसी संस्करण 4.7 से नीचे, का उपयोग करें -std=c++0x(इसके बजाय -std=c++0x)" मेरा मानना ​​है कि दूसरा "सी ++ 0x" के बजाय "सी ++ 11" होना चाहिए, लेकिन यह बदलना संभव नहीं है क्योंकि संपादन बहुत छोटा है।
zentrunix

1
@MasterMastic अगर std :: thread t1 (task1, "Hello") के बजाय हम फ़ंक्शन के संदर्भ को पास करते हुए std :: thread t1 (& task1, "Hello") का उपयोग करते हैं, तो क्या फर्क पड़ता है? क्या हमें इस मामले में फ़ंक्शन को सूचक के रूप में घोषित करना चाहिए?
user2452253

3
@ user2452253 यदि आप "task1" पास करते हैं, तो आप उस फ़ंक्शन को एक पॉइंटर पास करते हैं जिसे आप निष्पादित करना चाहते हैं (जो अच्छा है)। यदि आप "& task1" पास करते हैं, तो आप एक पॉइंटर को किसी फ़ंक्शन के पॉइंटर को पास करते हैं, और परिणाम शायद इतने सुंदर और बहुत अपरिभाषित नहीं होंगे (यह एक के बाद एक यादृच्छिक निर्देशों को निष्पादित करने की कोशिश करना होगा। सही संभावना के साथ) बस हो सकता है। नरक का प्रवेश द्वार खोलें)। आप वास्तव में केवल फ़ंक्शन पॉइंटर पास करना चाहते हैं (जहां पता शुरू होता है, उस पते के मूल्य के साथ एक पॉइंटर)। अगर वह चीजें साफ नहीं करता है, तो मुझे बताएं, और शुभकामनाएं!
MasterMastic

2
@curiousguy ठीक है, इसे करने का सही तरीका उस फ़ंक्शन के पॉइंटर को पास करना है जिसे आप चलाना चाहते हैं। इस मामले में फ़ंक्शन है task1। तो फ़ंक्शन पॉइंटर को भी निरूपित किया जाता है task1। लेकिन आपको इसे ऊपर लाने के लिए धन्यवाद क्योंकि मेरा मानना ​​है कि मैं गलत था और यह इसके बराबर है &task1, इसलिए यह कोई फर्क नहीं पड़ता कि आप किस रूप में लिखना चाहते हैं (यदि हां, तो मुझे लगता है कि फ़ंक्शन के सूचक को सूचक है &&task1- यह बुरा होगा )। प्रासंगिक प्रश्न
MasterMastic

80

खैर, तकनीकी रूप से ऐसी कोई भी वस्तु सी-स्टाइल थ्रेड लाइब्रेरी के ऊपर बनाई जा रही है क्योंकि C ++ ने केवल std::threadc ++ 0x में एक स्टॉक मॉडल को निर्दिष्ट किया था, जिसे अभी बंद किया गया था और अभी तक लागू नहीं किया गया है। समस्या कुछ हद तक प्रणालीगत है, तकनीकी रूप से मौजूदा c ++ मेमोरी मॉडल पर्याप्त रूप से परिभाषित शब्दार्थों के लिए 'सभी से पहले होने वाले' मामलों के लिए अनुमति देने के लिए पर्याप्त रूप से सख्त नहीं है। हंस बोएहम ने कुछ समय पहले इस विषय पर एक पेपर लिखा था और इस विषय पर c ++ 0x मानक को अंकित करने में महत्वपूर्ण भूमिका निभाई थी।

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

कहा कि कई क्रॉस-प्लेटफ़ॉर्म थ्रेड C ++ लाइब्रेरी हैं जो अभ्यास में ठीक काम करते हैं। इंटेल थ्रेड बिल्डिंग ब्लॉक्स में एक tbb :: थ्रेड ऑब्जेक्ट है जो बारीकी से c ++ 0x मानक का अनुमान लगाता है और Boost में एक बढ़ावा :: थ्रेड लाइब्रेरी है जो समान है।

http://www.threadingbuildingblocks.org/

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

बढ़ावा देने का उपयोग :: धागा आपको कुछ इस तरह मिलेगा:

#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;
}

8
बूस्ट थ्रेड बहुत अच्छा है - मेरी एकमात्र समस्या यह थी कि आप (जब मैंने आखिरी बार इसका इस्तेमाल किया था) वास्तव में देशी अंतर्निहित थ्रेड हैंडल का उपयोग कर सकते थे क्योंकि यह एक निजी वर्ग का सदस्य था! Win32 में सामान का एक टन है जिसके लिए आपको थ्रेडहैंडल की आवश्यकता है, इसलिए हमने हैंडल को सार्वजनिक करने के लिए इसे ट्वीक किया।
ओरियन एडवर्ड्स

4
बढ़ावा देने के साथ एक और समस्या :: धागा यह है कि जैसा कि मुझे याद है कि आपके पास नए धागे के स्टैक के आकार को निर्धारित करने की स्वतंत्रता नहीं है - एक सुविधा जो कि l ++ के मानक में भी शामिल नहीं है।
एडवर्ड KMETT

यह कोड मुझे एक बढ़ावा देता है :: इस पंक्ति के लिए गैर-अपवाद योग्य अपवाद: थ्रेड थ्रेड_1 = थ्रेड (कार्य 1); शायद यह इसलिए है क्योंकि मैं एक पुराने संस्करण (1.32) का उपयोग कर रहा हूं।
फ्रैंक

टास्क 1 इस दायरे में घोषित नहीं किया गया था?
जेक गैस्टन

20

POSIX ऑपरेटिंग सिस्टम के लिए एक POSIX लाइब्रेरी भी है। संगतता के लिए जाँच करें

#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;

}

संकलन के साथ

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


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

void doSomething(int id) {
    cout << id << "\n";
}

/**
 * Spawns n threads
 */
void spawnThreads(int n)
{
    std::vector<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();
    }
}

int main()
{
    spawnThreads(10);
}

13

जब एक 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
    }
}

ध्यान दें कि यह उदाहरण म्यूटेक्स या लॉकिंग में नहीं मिलता है।


2
इसे पोस्ट करने के लिए धन्यवाद। ध्यान दें कि उदाहरण विधि पर एक धागे को लागू करने का सामान्य रूप कुछ इस तरह से है: फू एफ; एसटीडी :: थ्रेड टी (और फू :: भागो, और एफ, आर्ग्स ...); (जहां फू एक वर्ग है जिसमें एक सदस्य समारोह के रूप में 'रन' () है)।
जे एलस्टन

इसे पोस्ट करने के लिए धन्यवाद। मैं गंभीरता से नहीं समझता कि सभी थ्रेडिंग उदाहरण वैश्विक कार्यों का उपयोग क्यों करते हैं।
hkBattousai

9

जब तक कोई वैश्विक नामपंखों में एक अलग फ़ंक्शन नहीं चाहता है, हम थ्रेड बनाने के लिए लंबो कार्यों का उपयोग कर सकते हैं।

लैम्ब्डा का उपयोग करके धागा बनाने का एक बड़ा फायदा यह है कि हमें एक तर्क सूची के रूप में स्थानीय मापदंडों को पारित करने की आवश्यकता नहीं है। हम उसी के लिए कैप्चर सूची का उपयोग कर सकते हैं और लैम्ब्डा की बंद संपत्ति जीवनचक्र का ध्यान रखेंगे।

यहाँ एक नमूना कोड है

int main() {
    int localVariable = 100;

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

    th.join();

    return 0;
}

अब तक, मैंने C ++ लैंबडास को विशेष रूप से सरल थ्रेड फ़ंक्शन के लिए थ्रेड बनाने का सबसे अच्छा तरीका पाया है


8

यह काफी हद तक आपके द्वारा उपयोग किए जाने वाले पुस्तकालय पर निर्भर करता है। उदाहरण के लिए, यदि आप wxWidgets लाइब्रेरी का उपयोग करते हैं, तो एक थ्रेड का निर्माण इस तरह दिखेगा:

class RThread : public wxThread {

public:
    RThread()
        : wxThread(wxTHREAD_JOINABLE){
    }
private:
    RThread(const RThread &copy);

public:
    void *Entry(void){
        //Do...

        return 0;
    }

};

wxThread *CreateThread() {
    //Create thread
    wxThread *_hThread = new RThread();

    //Start thread
    _hThread->Create();
    _hThread->Run();

    return _hThread;
}

यदि आपका मुख्य सूत्र CreateThread विधि को कॉल करता है, तो आप एक नया थ्रेड बनाएँगे जो आपके "एंट्री" पद्धति में कोड निष्पादित करना शुरू कर देगा। इसमें शामिल होने या इसे रोकने के लिए आपको ज्यादातर मामलों में थ्रेड का संदर्भ रखना होगा। अधिक जानकारी यहाँ: wxThread प्रलेखन


1
आप थ्रेड को हटाना भूल गए। शायद आप एक अलग धागा बनाने के लिए थे ?
18

1
हाँ ठीक है, मैंने कुछ कोड से कोड निकाला है, जो मैं वर्तमान में काम कर रहा हूं और निश्चित रूप से थ्रेड के संदर्भ को इसमें शामिल होने, रोकने और बाद में हटाने के लिए संग्रहीत किया गया है। धन्यवाद। :)
लॉरेंजकॉक 16
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.