การรวมเธรดใน C ++ 11


131

คำถามที่เกี่ยวข้อง :

เกี่ยวกับ C ++ 11:

เกี่ยวกับ Boost:


ฉันจะได้รับกลุ่มเธรดเพื่อส่งงานโดยไม่ต้องสร้างและลบซ้ำแล้วซ้ำอีกได้อย่างไร ซึ่งหมายความว่าเธรดแบบถาวรจะซิงโครไนซ์ใหม่โดยไม่ต้องเข้าร่วม


ฉันมีรหัสที่มีลักษณะดังนี้:

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
นี่คือคำถามที่เกี่ยวข้องและคำตอบของฉัน
didierc

1
คิดเกี่ยวกับการใช้ tbb (เป็น Intel แต่เป็นโอเพ่นซอร์สฟรีและทำในสิ่งที่คุณต้องการ: คุณเพียงแค่ส่งงาน (หารซ้ำ ๆ ไม่ได้) และไม่ต้องกังวลกับเธรด)
Walter

2
โครงการ FOSS นี้เป็นความพยายามของฉันในการสร้างไลบรารีเธรดพูลลองดูว่าคุณต้องการหรือไม่ -> code.google.com/p/threadpool11
Etherealone

เกิดอะไรขึ้นกับการใช้ tbb?
Walter

คำตอบ:


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 แบบส่วนหัวเดียวอ่านง่ายตรงไปตรงมากระชับและเป็นไปตามมาตรฐาน การทำงานที่ดี!
Jonathan H

@ vit-vit ช่วยยกตัวอย่างฟังก์ชั่นได้ไหม คุณจะผลักดันฟังก์ชันสมาชิกชั้นเรียนได้อย่างไรที่results[j] = p.push([&arr, j](int){ arr[j] +=2; });
Hani Goc

1
@HaniGoc เพียงจับอินสแตนซ์โดยอ้างอิง
Jonathan H

@ vit-vit ส่งคำขอให้ดึงข้อมูลเพื่อปรับปรุงเวอร์ชัน STL
Jonathan H

@ vit-vit: เป็นเรื่องยากที่จะติดต่อผู้ดูแลห้องสมุดนั้นหากมีคำถามคำใบ้คำใบ้
einpoklum

83

นี่คัดลอกมาจากคำตอบของฉันไปยังโพสต์อื่นที่คล้ายกันมากหวังว่ามันจะช่วยได้:

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

นี่คือลูป "while (true)" ที่รอคิวงาน

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

เมื่อคุณรวมส่วนผสมเหล่านี้คุณจะมีพูลเธรดแบบไดนามิกของคุณเอง เธรดเหล่านี้ทำงานอยู่เสมอรอให้งานทำ

ขออภัยหากมีข้อผิดพลาดทางไวยากรณ์ฉันพิมพ์รหัสเหล่านี้และฉันมีหน่วยความจำที่ไม่ดี ขออภัยที่ฉันไม่สามารถให้รหัสพูลเธรดที่สมบูรณ์แก่คุณได้ซึ่งจะเป็นการละเมิดความสมบูรณ์ของงานของฉัน

แก้ไข: เพื่อยุติพูลให้เรียกใช้วิธีการ shutdown ():

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() 
}

คุณมีเวกเตอร์ <thread> อย่างไรเมื่อ thread (const thread &) = delete?
Christopher Pisz

1
@ChristopherPisz std::vectorไม่ต้องการให้องค์ประกอบของมันสามารถคัดลอกได้ คุณสามารถใช้กับการย้ายเวกเตอร์เท่านั้นประเภท ( unique_ptr, thread, futureฯลฯ )
Daniel Langr

ในตัวอย่างข้างต้นคุณจะหยุดพูลได้อย่างไร ควรcondition.waitมองหาตัวแปรstop_และตรวจสอบด้วยif (stop_ == true) { break;}หรือไม่?
John

@ จอห์นโปรดดูวิธีการปิดระบบด้านบน
PhD AP EcE

2
ในการปิดเครื่อง () ควรเป็น thread_vector.clear (); แทน thread_vector.empty (); แก้ไข?
sudheerbb

63

กลุ่มของเธรดหมายความว่าเธรดทั้งหมดของคุณทำงานตลอดเวลากล่าวคือฟังก์ชันเธรดจะไม่ส่งคืน เพื่อให้เธรดมีความหมายที่จะทำคุณต้องออกแบบระบบการสื่อสารระหว่างเธรดทั้งเพื่อจุดประสงค์ในการบอกเธรดว่ามีสิ่งที่ต้องทำเช่นเดียวกับการสื่อสารข้อมูลงานจริง

โดยทั่วไปสิ่งนี้จะเกี่ยวข้องกับโครงสร้างข้อมูลบางอย่างพร้อมกันและแต่ละเธรดน่าจะเข้าสู่โหมดสลีปบนตัวแปรเงื่อนไขบางประเภทซึ่งจะได้รับการแจ้งเตือนเมื่อมีงานที่ต้องทำ เมื่อได้รับการแจ้งเตือนเธรดหนึ่งหรือหลายเธรดจะเริ่มทำงานกู้คืนงานจากโครงสร้างข้อมูลพร้อมกันประมวลผลและจัดเก็บผลลัพธ์ในรูปแบบที่คล้ายคลึงกัน

จากนั้นเธรดจะตรวจสอบต่อไปว่ายังมีงานต้องทำอีกหรือไม่และถ้าไม่กลับไปนอน

ผลที่สุดคือคุณต้องออกแบบทั้งหมดนี้ด้วยตัวเองเนื่องจากไม่มีแนวคิดที่เป็นธรรมชาติเกี่ยวกับ "งาน" ที่ใช้ได้ในระดับสากล มันค่อนข้างใช้งานได้ดีและมีปัญหาเล็กน้อยที่คุณต้องทำให้ถูกต้อง (คุณสามารถตั้งโปรแกรมใน Go ได้หากคุณชอบระบบที่ดูแลจัดการเธรดให้คุณอยู่เบื้องหลัง)


11
"คุณต้องออกแบบทั้งหมดนี้เอง" <- นั่นคือสิ่งที่ฉันพยายามหลีกเลี่ยงไม่ทำ แม้ว่า Goroutines จะดูยอดเยี่ยม
Yktula

2
@Yktula: มันเป็นงานที่ไม่สำคัญมาก ยังไม่ชัดเจนจากโพสต์ของคุณว่าคุณต้องการทำงานประเภทใดและนั่นเป็นพื้นฐานที่ลึกซึ้งในการแก้ปัญหา คุณสามารถใช้ Go ใน C ++ ได้ แต่มันจะเป็นสิ่งที่เฉพาะเจาะจงมากและครึ่งหนึ่งของผู้คนจะบ่นว่าพวกเขาต้องการสิ่งที่แตกต่างออกไป
Kerrek SB

19

เธรดพูลเป็นแกนกลางชุดของเธรดที่ผูกไว้กับฟังก์ชันที่ทำงานเป็นลูปเหตุการณ์ เธรดเหล่านี้จะรอให้งานถูกดำเนินการอย่างไม่มีที่สิ้นสุดหรือการสิ้นสุดของตัวเอง

งาน threadpool คือการจัดเตรียมอินเทอร์เฟซสำหรับส่งงานกำหนด (และอาจแก้ไข) นโยบายการรันงานเหล่านี้ (กฎการจัดตารางเวลาการสร้างอินสแตนซ์ของเธรดขนาดของพูล) และตรวจสอบสถานะของเธรดและทรัพยากรที่เกี่ยวข้อง

ดังนั้นสำหรับพูลอเนกประสงค์เราต้องเริ่มต้นด้วยการกำหนดว่างานคืออะไรเปิดใช้งานอย่างไรถูกขัดจังหวะผลลัพธ์คืออะไร (ดูแนวคิดของสัญญาและอนาคตสำหรับคำถามนั้น) เหตุการณ์ประเภทใดที่เธรดจะต้องตอบสนอง ว่าพวกเขาจะจัดการกับพวกเขาอย่างไรเหตุการณ์เหล่านี้จะถูกเลือกปฏิบัติอย่างไรจากเหตุการณ์ที่จัดการโดยงาน สิ่งนี้อาจซับซ้อนมากอย่างที่คุณเห็นและกำหนดข้อ จำกัด เกี่ยวกับวิธีการทำงานของเธรดเนื่องจากการแก้ปัญหามีส่วนเกี่ยวข้องมากขึ้นเรื่อย ๆ

เครื่องมือในปัจจุบันสำหรับการจัดการเหตุการณ์นั้นค่อนข้างจะเป็นแบบ barebones (*): primitives เช่น mutexes ตัวแปรเงื่อนไขและ abstractions บางส่วนที่อยู่ด้านบน (ล็อคอุปสรรค) แต่ในบางกรณีการละเว้นเหล่านี้อาจไม่เหมาะสม (ดูคำถามที่เกี่ยวข้องนี้) และต้องเปลี่ยนกลับไปใช้แบบดั้งเดิม

ต้องจัดการปัญหาอื่น ๆ ด้วย:

  • สัญญาณ
  • I / O
  • ฮาร์ดแวร์ (ความสัมพันธ์ของโปรเซสเซอร์การตั้งค่าที่แตกต่างกัน)

สิ่งเหล่านี้จะมีผลอย่างไรในการตั้งค่าของคุณ?

คำตอบสำหรับคำถามที่คล้ายกันนี้ชี้ให้เห็นถึงการนำไปใช้งานที่มีอยู่เพื่อเพิ่มประสิทธิภาพและมาตรฐาน

ฉันเสนอการใช้เธรดพูลที่หยาบคายมากสำหรับคำถามอื่นซึ่งไม่ได้แก้ไขปัญหามากมายที่ระบุไว้ข้างต้น คุณอาจต้องการสร้างมันขึ้นมา คุณอาจต้องการดูเฟรมเวิร์กที่มีอยู่ในภาษาอื่นเพื่อค้นหาแรงบันดาลใจ


(*) ฉันไม่เห็นว่าเป็นปัญหา แต่ค่อนข้างตรงกันข้าม ฉันคิดว่ามันเป็นจิตวิญญาณของ 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
ขอบคุณ! สิ่งนี้ช่วยให้ฉันเริ่มต้นการดำเนินการเธรดแบบขนานได้มาก ฉันลงเอยด้วยการใช้การใช้งานเวอร์ชันที่แก้ไขเล็กน้อย
Robbie Capps

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 คือการใช้งานที่มีประสิทธิภาพมากหรือจริงๆแล้วคือชุดของ Wrapper เฉพาะแพลตฟอร์ม (เช่นมันรวมพอร์ต I / O ที่สมบูรณ์บน Windows)


2
การเพิ่มประสิทธิภาพนั้นจำเป็นกับ C ++ 11 หรือไม่? จะไม่พูดว่าstd::threadพอเพียง?
einpoklum

ไม่มีสิ่งที่เทียบเท่าในstdสำหรับboost::thread_group. boost::thread_groupคือชุดของboost::threadอินสแตนซ์ แต่แน่นอนว่ามันง่ายมากที่จะแทนที่boost::thread_groupด้วย a vectorof std::threads
rustyx

3

แก้ไข: ตอนนี้ต้องใช้ C ++ 17 และแนวคิด (ณ วันที่ 9/12/59 มีเพียง g ++ 6.0+ ก็เพียงพอแล้ว)

อย่างไรก็ตามการหักเทมเพลตมีความแม่นยำกว่ามากเนื่องจากเป็นเช่นนั้นจึงคุ้มค่ากับความพยายามในการรับคอมไพเลอร์รุ่นใหม่ ฉันยังไม่พบฟังก์ชันที่ต้องใช้อาร์กิวเมนต์แม่แบบที่ชัดเจน

ตอนนี้ยังใช้วัตถุที่เรียกได้ที่เหมาะสม ( และยังคงเป็นแบบคงที่ปลอดภัย !!! )

ตอนนี้ยังมีพูลเธรดลำดับความสำคัญของเธรดสีเขียวที่เป็นทางเลือกโดยใช้ API เดียวกัน คลาสนี้เป็น POSIX เท่านั้น ใช้ucontext_tAPI สำหรับการสลับงาน userspace


ฉันสร้างห้องสมุดง่ายๆสำหรับสิ่งนี้ ตัวอย่างการใช้งานมีให้ด้านล่าง (ฉันตอบคำถามนี้เพราะเป็นหนึ่งในสิ่งที่ฉันพบก่อนที่ฉันจะตัดสินใจว่าจำเป็นต้องเขียนด้วยตัวเอง)

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
ดูน่าทึ่ง แต่จะดีมากหากเปรียบเทียบกับส่วนหัวของ vit-vit!
Jonathan H

1
@ Sh3ljohn จากการเหลือบมองดูเหมือนว่าโดยพื้นฐานแล้วมันเหมือนกันใน API vit-vit ใช้คิวฟรีของบูสต์ซึ่งดีกว่าของฉัน (แต่เป้าหมายของฉันคือทำโดยเฉพาะกับ std :: * เท่านั้นฉันคิดว่าฉันสามารถใช้คิวแบบไม่มีล็อกได้ด้วยตัวเอง แต่ฟังดูยากและเกิดข้อผิดพลาดได้ง่าย) นอกจากนี้ vit-vit ยังไม่มี. cpp ที่เกี่ยวข้องซึ่ง ใช้ง่ายกว่าสำหรับคนที่ไม่รู้ว่ากำลังทำอะไรอยู่ (เช่นgithub.com/Tyler-Hardin/thread_pool/issues/1 )
Tyler

นอกจากนี้เขา / เธอยังมีโซลูชันเฉพาะ stl ที่ฉันใช้ในช่วงสองสามชั่วโมงที่ผ่านมาในตอนแรกมันดูซับซ้อนกว่าของคุณด้วยตัวชี้ที่ใช้ร่วมกันทั่วทุกที่ แต่สิ่งนี้จำเป็นสำหรับการจัดการการปรับขนาดแบบร้อนอย่างถูกต้อง
Jonathan H

@ Sh3ljohn อาฉันไม่ได้สังเกตเห็นการปรับขนาดที่ร้อนแรง นั่นเป็นสิ่งที่ดี ฉันเลือกที่จะไม่กังวลเกี่ยวกับเรื่องนี้เพราะมันไม่ได้อยู่ในกรณีการใช้งานที่ตั้งใจไว้ (ฉันไม่สามารถนึกถึงกรณีที่ฉันต้องการปรับขนาดเป็นการส่วนตัว แต่อาจเกิดจากการขาดจินตนาการ)
Tyler

1
ตัวอย่างกรณีการใช้งาน: คุณกำลังเรียกใช้ RESTful API บนเซิร์ฟเวอร์และจำเป็นต้องลดการจัดสรรทรัพยากรชั่วคราวเพื่อวัตถุประสงค์ในการบำรุงรักษาโดยไม่จำเป็นต้องปิดบริการทั้งหมด
Jonathan H

3

นี่เป็นอีกหนึ่งการใช้งานเธรดพูลที่ง่ายมากเข้าใจง่ายและใช้งานได้ใช้ไลบรารีมาตรฐาน C ++ 11 เท่านั้นและสามารถดูหรือแก้ไขเพื่อการใช้งานของคุณได้ควรเป็นตัวเริ่มต้นที่ดีหากคุณต้องการใช้เธรด สระว่ายน้ำ:

https://github.com/progschj/ThreadPool


3

คุณสามารถใช้thread_poolจากไลบรารีบูสต์ :

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, []() {
      ...
    });
}

คุณยังสามารถใช้threadpoolจากชุมชนโอเพนซอร์ส:

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

เธรดพูลที่ไม่มีการอ้างอิงนอก STL เป็นไปได้ทั้งหมด ฉันเพิ่งเขียนไลบรารี threadpool ส่วนหัวขนาดเล็กเพื่อแก้ไขปัญหาเดียวกัน รองรับการปรับขนาดพูลแบบไดนามิก (การเปลี่ยนจำนวนคนงานที่รันไทม์) การรอการหยุดการหยุดชั่วคราวการทำงานต่อและอื่น ๆ ฉันหวังว่าคุณพบว่ามีประโยชน์.


ดูเหมือนว่าคุณได้ลบบัญชี github ของคุณแล้ว (หรือลิงก์ผิด) คุณได้ย้ายรหัสนี้ไปที่อื่นหรือไม่?
rtpax

1
@rtpax ฉันย้าย repo - ฉันอัปเดตคำตอบเพื่อสะท้อนถึงสิ่งนั้น
cantordust
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.