C ++ 11 में थ्रेड पूलिंग


130

प्रासंगिक प्रश्न :

C ++ 11 के बारे में:

बूस्ट के बारे में:


मुझे बार-बार बनाने और हटाने के बिना, कार्यों को भेजने के लिए थ्रेड्स का एक पूल कैसे मिलता है ? इसका अर्थ है बिना शामिल हुए पुन: सिंक्रनाइज़ करने के लिए लगातार सूत्र।


मेरे पास कोड है जो इस तरह दिखता है:

namespace {
  std::vector<std::thread> workers;

  int total = 4;
  int arr[4] = {0};

  void each_thread_does(int i) {
    arr[i] += 2;
  }
}

int main(int argc, char *argv[]) {
  for (int i = 0; i < 8; ++i) { // for 8 iterations,
    for (int j = 0; j < 4; ++j) {
      workers.push_back(std::thread(each_thread_does, j));
    }
    for (std::thread &t: workers) {
      if (t.joinable()) {
        t.join();
      }
    }
    arr[4] = std::min_element(arr, arr+4);
  }
  return 0;
}

प्रत्येक पुनरावृत्तियों को बनाने और शामिल करने के बजाय, मैं अपने कार्यकर्ता को प्रत्येक पुनरावृत्ति को कार्य भेजना पसंद करता हूँ और केवल एक बार उन्हें बनाता हूँ।


1
यहाँ एक संबंधित प्रश्न और मेरा उत्तर है।
दीदीक

1
tbb (यह इंटेल है, लेकिन स्वतंत्र और खुला स्रोत है, और वास्तव में आप जो चाहते हैं उसका उपयोग करने के बारे में सोचा: आप बस (पुनरावर्ती विभाज्य) कार्य सबमिट करें और थ्रेड्स के बारे में चिंता न करें)?
वाल्टर

2
यह FOSS प्रोजेक्ट एक थ्रेड पूल लाइब्रेरी बनाने का मेरा प्रयास है, अगर आप चाहें तो इसे देखें। -> code.google.com/p/threadpool11
Etherealone

Tbb का उपयोग करने में क्या गलत है?
वाल्टर

जवाबों:


84

आप C ++ थ्रेड पूल लाइब्रेरी, https://github.com/vit-vit/ctpl का उपयोग कर सकते हैं ।

फिर आपके द्वारा लिखे गए कोड को निम्नलिखित के साथ बदला जा सकता है

#include <ctpl.h>  // or <ctpl_stl.h> if ou do not have Boost library

int main (int argc, char *argv[]) {
    ctpl::thread_pool p(2 /* two threads in the pool */);
    int arr[4] = {0};
    std::vector<std::future<void>> results(4);
    for (int i = 0; i < 8; ++i) { // for 8 iterations,
        for (int j = 0; j < 4; ++j) {
            results[j] = p.push([&arr, j](int){ arr[j] +=2; });
        }
        for (int j = 0; j < 4; ++j) {
            results[j].get();
        }
        arr[4] = std::min_element(arr, arr + 4);
    }
}

आपको थ्रेड्स की वांछित संख्या मिल जाएगी और पुनरावृत्तियों पर उन्हें बार-बार नहीं बनाएंगे और हटाएंगे।


11
यह उत्तर होना चाहिए; एकल-हेडर, पठनीय, सीधा, संक्षिप्त और मानक-अनुरूप C ++ 11 पुस्तकालय। अच्छा कार्य!
जोनाथन एच

@ vit-vit क्या आप कृपया एक फ़ंक्शन के साथ एक उदाहरण दे सकते हैं? कैसे आप एक धक्का है वर्ग के सदस्य समारोह मेंresults[j] = p.push([&arr, j](int){ arr[j] +=2; });
हानी जीओसी

1
@HaniGoc केवल संदर्भ द्वारा उदाहरण को कैप्चर करें।
जोनाथन एच

@ vit-vit आपने STL संस्करण को बेहतर बनाने के लिए एक पुल अनुरोध भेजा है।
जोनाथन एच

@ vit-vit: प्रश्नों के साथ उस लाइब्रेरी के अनुचर से संपर्क करना मुश्किल है, संकेत संकेत।
einpoklum

82

यह मेरे जवाब से एक और बहुत ही समान पोस्ट पर कॉपी किया गया है, आशा है कि यह मदद कर सकता है:

1) एक प्रणाली का समर्थन कर सकते हैं धागे की अधिकतम संख्या के साथ शुरू करें:

int Num_Threads =  thread::hardware_concurrency();

2) एक कुशल थ्रेडपूल कार्यान्वयन के लिए, एक बार थ्रेड्स को Num_Threads के अनुसार बनाया जाता है, यह बेहतर है कि नए को न बनाएं, या पुराने लोगों को नष्ट न करें (शामिल होकर)। प्रदर्शन पेनल्टी होगी, हो सकता है कि आपका आवेदन धारावाहिक संस्करण की तुलना में धीमा हो जाए।

प्रत्येक C ++ 11 थ्रेड को एक अनंत लूप के साथ अपने फ़ंक्शन में चलना चाहिए, लगातार नए कार्यों को हथियाने और चलाने के लिए इंतजार करना चाहिए।

इस तरह के फ़ंक्शन को थ्रेड पूल से कैसे जोड़ा जाए:

int Num_Threads = thread::hardware_concurrency();
vector<thread> Pool;
for(int ii = 0; ii < Num_Threads; ii++)
{  Pool.push_back(thread(Infinite_loop_function));}

3) Infinite_loop_function

यह एक "जबकि (सच्चा)" लूप है जो कार्य कतार की प्रतीक्षा कर रहा है

void The_Pool:: Infinite_loop_function()
{
    while(true)
    {
        {
            unique_lock<mutex> lock(Queue_Mutex);

            condition.wait(lock, []{return !Queue.empty() || terminate_pool});
            Job = Queue.front();
            Queue.pop();
        }
        Job(); // function<void()> type
    }
};

4) अपनी कतार में नौकरी जोड़ने के लिए एक फ़ंक्शन बनाएं

void The_Pool:: Add_Job(function<void()> New_Job)
{
    {
        unique_lock<mutex> lock(Queue_Mutex);
        Queue.push(New_Job);
    }
    condition.notify_one();
}

5) अपने कतार में एक मनमाना कार्य बाँधें

Pool_Obj.Add_Job(std::bind(&Some_Class::Some_Method, &Some_object));

एक बार जब आप इन सामग्रियों को एकीकृत कर लेते हैं, तो आपका अपना गतिशील थ्रेडिंग पूल होता है। ये सूत्र हमेशा चलते हैं, नौकरी करने के लिए इंतजार करते हैं।

यदि कुछ वाक्यविन्यास त्रुटियां हैं, तो मैं माफी मांगता हूं, मैंने इन कोड को टाइप किया है और मेरे पास एक खराब मेमोरी है। क्षमा करें कि मैं आपको पूर्ण थ्रेड पूल कोड प्रदान नहीं कर सकता, जो मेरी नौकरी की अखंडता का उल्लंघन होगा।

संपादित करें: पूल को समाप्त करने के लिए, शटडाउन () विधि को कॉल करें:

XXXX::shutdown(){
{
    unique_lock<mutex> lock(threadpool_mutex);
    terminate_pool = true;} // use this flag in condition.wait

    condition.notify_all(); // wake up all threads.

    // Join all threads.
    for(std::thread &every_thread : thread_vector)
    {   every_thread.join();}

    thread_vector.clear();  
    stopped = true; // use this flag in destructor, if not set, call shutdown() 
}

जब आपके पास वेक्टर (थ्रेड) हो तो थ्रेड (कास्ट थ्रेड &) = डिलीट कैसे करें?
क्रिस्टोफर पिस

1
@ChristopherPisz std::vectorको इसके तत्वों की नकल करने की आवश्यकता नहीं है। आप इस कदम-केवल प्रकार (साथ वैक्टर का उपयोग कर सकते unique_ptr, thread, future, आदि)।
डैनियल लैंगर

अपने उपरोक्त उदाहरण में, आप पूल को कैसे रोकेंगे? क्या condition.waitएक चर भी देखना चाहिए stop_और जांचना चाहिए if (stop_ == true) { break;}?
जॉन

@ जॉन, कृपया ऊपर शटडाउन विधि देखें।
पीएचडी एपी एके

2
शटडाउन () में, यह थ्रेड_वेक्टर.क्लेयर () होना चाहिए; थ्रेड_वेक्टर के बजाय। खाली (); सही बात?
सुधीरब

63

थ्रेड्स के एक पूल का मतलब है कि आपके सभी धागे हर समय चल रहे हैं - दूसरे शब्दों में, थ्रेड फ़ंक्शन कभी नहीं लौटता है। थ्रेड्स को कुछ सार्थक करने के लिए, आपको इंटर-थ्रेड कम्युनिकेशन की एक प्रणाली डिजाइन करनी होगी, दोनों ही उस थ्रेड को बताने के उद्देश्य से जो कुछ करने के लिए है, साथ ही साथ वास्तविक कार्य डेटा को संप्रेषित करने के लिए भी है।

आमतौर पर इसमें कुछ प्रकार के समवर्ती डेटा संरचना शामिल होती है, और प्रत्येक थ्रेड संभवतः किसी प्रकार की स्थिति चर पर सो जाएगा, जिसे तब सूचित किया जाएगा जब काम करना है। अधिसूचना प्राप्त होने पर, एक या कई धागे जाग जाते हैं, समवर्ती डेटा संरचना से एक कार्य को पुनर्प्राप्त करते हैं, इसे संसाधित करते हैं, और परिणाम को एक अनुरूप फैशन में संग्रहीत करते हैं।

फिर थ्रेड यह जांचने के लिए जाएगा कि क्या और भी काम करना है, और अगर वापस नहीं जाना है।

अपशॉट यह है कि आपको यह सब खुद ही डिजाइन करना होगा, क्योंकि सार्वभौमिक रूप से लागू होने वाले "काम" की स्वाभाविक धारणा नहीं है। यह काफी काम का है, और कुछ सूक्ष्म मुद्दे हैं जिन्हें आपको ठीक करना है। (आप गो में प्रोग्राम कर सकते हैं यदि आप एक ऐसी प्रणाली पसंद करते हैं जो पर्दे के पीछे आपके लिए थ्रेड मैनेजमेंट का ख्याल रखती है।)


11
"आपको यह सब स्वयं डिजाइन करना होगा" <- यही मैं करने से बचने की कोशिश कर रहा हूं। हालांकि, Goroutines शानदार लगते हैं।
युकुला

2
@Yutula: खैर, यह एक बहुत ही गैर-तुच्छ कार्य है। यह आपके पोस्ट से स्पष्ट नहीं है कि आप किस तरह का काम करना चाहते हैं, और यह समाधान के लिए मौलिक रूप से मौलिक है। आप गो ++ को C ++ में लागू कर सकते हैं, लेकिन यह एक बहुत ही विशिष्ट बात होगी, और आधे लोग शिकायत करेंगे कि वे कुछ अलग करना चाहते हैं।
केरेक एसबी

19

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

थ्रेडपूल का काम नौकरियों को प्रस्तुत करने के लिए एक इंटरफ़ेस प्रदान करना है, और इन नौकरियों को चलाने की नीति को परिभाषित करना (और शायद संशोधित करना), शेड्यूलिंग नियम, थ्रेड तात्कालिकता, पूल का आकार), और थ्रेड्स और संबंधित संसाधनों की स्थिति की निगरानी करना है।

एक बहुमुखी पूल के लिए, किसी को यह निर्धारित करके शुरू करना चाहिए कि कोई कार्य क्या है, इसे कैसे लॉन्च किया जाता है, बाधित किया जाता है, इसका क्या परिणाम होता है (उस प्रश्न के लिए वादे और भविष्य की धारणा देखें), थ्रेड्स को किस तरह की घटनाओं का जवाब देना होगा , वे उन्हें कैसे संभालेंगे, कैसे इन घटनाओं को कार्यों द्वारा नियंत्रित लोगों से भेदभाव किया जाएगा। यह काफी जटिल हो सकता है जैसा कि आप देख सकते हैं, और इस पर प्रतिबंध लगा सकते हैं कि थ्रेड्स कैसे काम करेंगे, क्योंकि समाधान अधिक से अधिक शामिल हो जाता है।

घटनाओं को संभालने के लिए वर्तमान टूलींग काफी नंगे है (*): म्यूटेक्स, प्राइमरी वैरिएबल और उस के शीर्ष पर कुछ सार (ताले, बैरियर) जैसी प्राइमरी। लेकिन कुछ मामलों में, ये गर्भपात अनफिट हो सकते हैं (यह संबंधित प्रश्न देखें ), और किसी को आदिम का उपयोग करने के लिए वापस करना होगा।

अन्य समस्याओं को भी प्रबंधित करना होगा:

  • संकेत
  • आई / ओ
  • हार्डवेयर (प्रोसेसर आत्मीयता, विषम सेटअप)

यह आपकी सेटिंग में कैसे चलेगा?

इसी तरह के सवाल का जवाब मौजूदा कार्यान्वयन के लिए है जो बढ़ावा और स्टाल के लिए है।

मैंने एक और प्रश्न के लिए एक थ्रेडपूल के बहुत क्रूड कार्यान्वयन की पेशकश की , जो ऊपर उल्लिखित कई समस्याओं को संबोधित नहीं करता है। आप इस पर निर्माण करना चाह सकते हैं। प्रेरणा पाने के लिए आप अन्य भाषाओं में विद्यमान रूपरेखाओं को देखना चाहते हैं।


(*) मैं नहीं देखता कि एक समस्या के रूप में, इसके विपरीत। मुझे लगता है कि यह C से विरासत में मिली C ++ की बहुत भावना है।


4
Follwoing [PhD EcE](https://stackoverflow.com/users/3818417/phd-ece) suggestion, I implemented the thread pool:

function_pool.h

#pragma once
#include <queue>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <cassert>

class Function_pool
{

private:
    std::queue<std::function<void()>> m_function_queue;
    std::mutex m_lock;
    std::condition_variable m_data_condition;
    std::atomic<bool> m_accept_functions;

public:

    Function_pool();
    ~Function_pool();
    void push(std::function<void()> func);
    void done();
    void infinite_loop_func();
};

function_pool.cpp

#include "function_pool.h"

Function_pool::Function_pool() : m_function_queue(), m_lock(), m_data_condition(), m_accept_functions(true)
{
}

Function_pool::~Function_pool()
{
}

void Function_pool::push(std::function<void()> func)
{
    std::unique_lock<std::mutex> lock(m_lock);
    m_function_queue.push(func);
    // when we send the notification immediately, the consumer will try to get the lock , so unlock asap
    lock.unlock();
    m_data_condition.notify_one();
}

void Function_pool::done()
{
    std::unique_lock<std::mutex> lock(m_lock);
    m_accept_functions = false;
    lock.unlock();
    // when we send the notification immediately, the consumer will try to get the lock , so unlock asap
    m_data_condition.notify_all();
    //notify all waiting threads.
}

void Function_pool::infinite_loop_func()
{
    std::function<void()> func;
    while (true)
    {
        {
            std::unique_lock<std::mutex> lock(m_lock);
            m_data_condition.wait(lock, [this]() {return !m_function_queue.empty() || !m_accept_functions; });
            if (!m_accept_functions && m_function_queue.empty())
            {
                //lock will be release automatically.
                //finish the thread loop and let it join in the main thread.
                return;
            }
            func = m_function_queue.front();
            m_function_queue.pop();
            //release the lock
        }
        func();
    }
}

main.cpp

#include "function_pool.h"
#include <string>
#include <iostream>
#include <mutex>
#include <functional>
#include <thread>
#include <vector>

Function_pool func_pool;

class quit_worker_exception : public std::exception {};

void example_function()
{
    std::cout << "bla" << std::endl;
}

int main()
{
    std::cout << "stating operation" << std::endl;
    int num_threads = std::thread::hardware_concurrency();
    std::cout << "number of threads = " << num_threads << std::endl;
    std::vector<std::thread> thread_pool;
    for (int i = 0; i < num_threads; i++)
    {
        thread_pool.push_back(std::thread(&Function_pool::infinite_loop_func, &func_pool));
    }

    //here we should send our functions
    for (int i = 0; i < 50; i++)
    {
        func_pool.push(example_function);
    }
    func_pool.done();
    for (unsigned int i = 0; i < thread_pool.size(); i++)
    {
        thread_pool.at(i).join();
    }
}

2
धन्यवाद! यह वास्तव में मुझे समानांतर थ्रेडिंग ऑपरेशन के साथ आरंभ करने में मदद करता है। मैंने आपके कार्यान्वयन के थोड़े संशोधित संस्करण का उपयोग करके समाप्त कर दिया।
रॉबी कैप्स

3

ऐसा कुछ मदद कर सकता है (एक काम कर रहे ऐप से लिया गया)।

#include <memory>
#include <boost/asio.hpp>
#include <boost/thread.hpp>

struct thread_pool {
  typedef std::unique_ptr<boost::asio::io_service::work> asio_worker;

  thread_pool(int threads) :service(), service_worker(new asio_worker::element_type(service)) {
    for (int i = 0; i < threads; ++i) {
      auto worker = [this] { return service.run(); };
      grp.add_thread(new boost::thread(worker));
    }
  }

  template<class F>
  void enqueue(F f) {
    service.post(f);
  }

  ~thread_pool() {
    service_worker.reset();
    grp.join_all();
    service.stop();
  }

private:
  boost::asio::io_service service;
  asio_worker service_worker;
  boost::thread_group grp;
};

आप इसे इस तरह से उपयोग कर सकते हैं:

thread_pool pool(2);

pool.enqueue([] {
  std::cout << "Hello from Task 1\n";
});

pool.enqueue([] {
  std::cout << "Hello from Task 2\n";
});

ध्यान रखें कि एक कुशल एसिंक्रोनस कतारिंग तंत्र को फिर से बनाना तुच्छ नहीं है।

Boost :: asio :: io_service एक बहुत ही कुशल कार्यान्वयन है, या वास्तव में प्लेटफ़ॉर्म-विशिष्ट आवरणों का एक संग्रह है (जैसे कि यह विंडोज़ पर I / O पूरा करने वाले बंदरगाहों को लपेटता है)।


2
क्या C ++ 11 के साथ इतना बढ़ावा जरूरी है? कहना, एक std::threadपर्याप्त नहीं होगा?
einpoklum

वहाँ में कोई बराबर है stdके लिए boost::thread_group। उदाहरणों boost::thread_groupका एक संग्रह है boost::thread। लेकिन ज़ाहिर है, इसे बदलना बहुत आसान है boost::thread_groupएक साथ vectorकी std::threadहै।
रस्टीक्स

3

संपादित करें: इसके लिए अब C ++ 17 और अवधारणाओं की आवश्यकता है। (9/12/16 तक, केवल g ++ 6.0+ पर्याप्त है।)

टेम्पलेट कटौती इसके कारण बहुत अधिक सटीक है, हालांकि, इसलिए यह एक नया संकलक प्राप्त करने के प्रयास के लायक है। मुझे अभी तक एक फ़ंक्शन नहीं मिला है जिसमें स्पष्ट टेम्पलेट तर्क की आवश्यकता होती है।

यह अब किसी भी उपयुक्त कॉल करने योग्य वस्तु को ले जाता है ( और अभी भी सांख्यिकीय रूप से टाइप किया जाता है !!! )।

इसमें अब उसी API का उपयोग करके वैकल्पिक ग्रीन थ्रेडिंग प्राथमिकता थ्रेड पूल भी शामिल है। यह वर्ग POSIX ही है, हालांकि। यह ucontext_tयूजरस्पेस टास्क स्विचिंग के लिए एपीआई का उपयोग करता है ।


मैंने इसके लिए एक साधारण पुस्तकालय बनाया। उपयोग का एक उदाहरण नीचे दिया गया है। (मैं इसका उत्तर दे रहा हूं क्योंकि यह उन चीजों में से एक था जो मैंने तय करने से पहले पाया था कि इसे स्वयं लिखना आवश्यक है।)

bool is_prime(int n){
  // Determine if n is prime.
}

int main(){
  thread_pool pool(8); // 8 threads

  list<future<bool>> results;
  for(int n = 2;n < 10000;n++){
    // Submit a job to the pool.
    results.emplace_back(pool.async(is_prime, n));
  }

  int n = 2;
  for(auto i = results.begin();i != results.end();i++, n++){
    // i is an iterator pointing to a future representing the result of is_prime(n)
    cout << n << " ";
    bool prime = i->get(); // Wait for the task is_prime(n) to finish and get the result.
    if(prime)
      cout << "is prime";
    else
      cout << "is not prime";
    cout << endl;
  }  
}

आप asyncकिसी भी फ़ंक्शन को किसी भी (या शून्य) रिटर्न मान और किसी भी (या नहीं) तर्कों के साथ पास कर सकते हैं और यह एक संगत रिटर्न देगा std::future। परिणाम प्राप्त करने के लिए (या किसी कार्य के पूरा होने तक प्रतीक्षा करें) जिसे आप कहते हैंget() भविष्य पर करते हैं।

यहाँ github: https://github.com/Tyler-Hardin/thread_pool है


1
अद्भुत लग रहा है, लेकिन इन-विट-विट हेडर की तुलना करना बहुत अच्छा होगा!
जोनाथन एच

1
@ Sh3ljohn, इस पर नज़र रखने से, ऐसा प्रतीत होता है कि वे मूल रूप से एपीआई में समान हैं। vit-vit बूस्ट की लॉकफ्री कतार का उपयोग करता है, जो खान से बेहतर है। (लेकिन मेरा लक्ष्य विशेष रूप से इसे std :: * के साथ करना था। मुझे लगता है कि मैं खुद लॉकफ्री कतार को लागू कर सकता हूं, लेकिन यह कठिन और त्रुटि वाला लगता है।) इसके अलावा, vit-vit का कोई संबद्ध .cpp नहीं है, जो उन लोगों के लिए उपयोग करना सरल है जो नहीं जानते कि वे क्या कर रहे हैं। (जैसे github.com/Tyler-Hardin/thread_pool/issues/1 )
टायलर

उसका / उसके पास एक स्टाल-ओनली सॉल्यूशन भी है, जिसे मैं पिछले कुछ घंटों से फोर्क कर रहा हूं, पहले तो यह आपके लिए जगह-जगह पर साझा किए गए पॉइंटर्स के साथ आपसे कहीं अधिक जटिल लग रहा था, लेकिन इसे वास्तव में हॉट-रिसाइज को ठीक से हैंडल करने की आवश्यकता है।
जोनाथन एच

@ Sh3ljohn, आह, मैंने गर्म आकार बदलने पर ध्यान नहीं दिया। वह अच्छा हैं। मैंने इसके बारे में चिंता नहीं करने का फैसला किया क्योंकि यह वास्तव में उपयोग किए गए मामले में नहीं है। (मैं एक ऐसे मामले के बारे में नहीं सोच सकता, जहां मैं व्यक्तिगत रूप से आकार बदलना चाहता हूं, लेकिन यह कल्पना की कमी के कारण हो सकता है।)
टायलर

1
उदाहरण उपयोग-मामला: आप एक सर्वर पर एक RESTful API चला रहे हैं और पूरी तरह से सेवा को बंद करने की आवश्यकता के बिना, रखरखाव उद्देश्यों के लिए संसाधन आवंटन को कम करने की आवश्यकता है।
जोनाथन एच

3

यह एक और थ्रेड पूल कार्यान्वयन है जो बहुत ही सरल, समझने और उपयोग करने में आसान है, केवल C ++ 11 मानक पुस्तकालय का उपयोग करता है, और आपके उपयोगों के लिए इसे देखा या संशोधित किया जा सकता है, यदि आप थ्रेड का उपयोग करना चाहते हैं तो एक अच्छा स्टार्टर होना चाहिए। पूल:

https://github.com/progschj/ThreadPool


3

आप बूस्ट लाइब्रेरी से थ्रेड_पूल का उपयोग कर सकते हैं :

void my_task(){...}

int main(){
    int threadNumbers = thread::hardware_concurrency();
    boost::asio::thread_pool pool(threadNumbers);

    // Submit a function to the pool.
    boost::asio::post(pool, my_task);

    // Submit a lambda object to the pool.
    boost::asio::post(pool, []() {
      ...
    });
}

आप भी उपयोग कर सकते हैं ओपन सोर्स समुदाय से थ्रेडपूल का :

void first_task() {...}    
void second_task() {...}

int main(){
    int threadNumbers = thread::hardware_concurrency();
    pool tp(threadNumbers);

    // Add some tasks to the pool.
    tp.schedule(&first_task);
    tp.schedule(&second_task);
}

1

एसटीएल के बाहर कोई निर्भरता वाला एक थ्रेडपुल पूरी तरह से संभव है। मैंने हाल ही में एक ही हेडर-केवल थ्रेडपूल लाइब्रेरी लिखी थी, जो उसी समस्या को हल करने के लिए थी। यह गतिशील पूल का आकार बदलने (रनटाइम पर श्रमिकों की संख्या में बदलाव), प्रतीक्षा, रुकने, रुकने, फिर से शुरू करने और इतने पर समर्थन करता है। मुझे उम्मीद है कि आप इसे उपयोगी पाएँ।


ऐसा लगता है कि आपने अपना github खाता हटा दिया है (या लिंक गलत है)। क्या आपने इस कोड को कहीं और स्थानांतरित कर दिया है?
rtpax

1
@ आर्टपैक्स मैंने रेपो को स्थानांतरित किया - मैंने उस उत्तर को प्रतिबिंबित करने के लिए अद्यतन किया।
छावनी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.