討論區快速選單
知識庫快速選單
政府補助!學嵌入式+物聯網 網路投保旅行平安險 軟體開發過程中有哪些資安漏洞?
[ 回上頁 ] [ 討論區發言規則 ]
[分享] thread 控管 ThreadLimit
更改我的閱讀文章字型大小
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1034 | 人氣 3227 | 評價 1260 | 評價/貼文 1.22 | 送出評價 27 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/4/6 下午 04:25:41
這個小程式純粹只是設限 thread 可產生的個數,沒任務可執行就會結束,有別於 ThreadPool 結束前 Thread 都會一直存在。

比起純粹使用 std::thread 效率應該會好一些,因 std::thread 和任務是一對一,只要任務結束,thread 也會結束。ThreadLimit 則是把任務放入 list,要 list 中的任務執行完,thread 才會結束。而 ThreadPool 效率是最好的,但 ThreadPool 會一直佔用 thread。

對於不會結束的任務,請不要用 ThreadLimit,否則會佔用 ThreadLimit 的額度,這種任務請直接使用 std::thread。
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1034 | 人氣 3227 | 評價 1260 | 評價/貼文 1.22 | 送出評價 27 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/4/6 下午 04:27:10
#include <functional>  // std::bind
#include <list>
#include <thread>
#include <mutex>
#include <memory>
#include <chrono>


template <unsigned int N>
class ThreadLimit
{
 // 包裹要執行的任務
 class ThreadNode
 {
  std::function<void(void)> Func;

 public:
  // Constructor
  ThreadNode(const std::function<void(void)> &b)
   :Func(b)
  {}
  // Destructor
  virtual ~ThreadNode() {}

  // 執行任務
  void toDo() const
  {
   Func();
  }
 };


 std::mutex m_ThreadLimit_mutex;

 // 待處理的任務
 std::list< std::shared_ptr<ThreadNode> > m_ThreadNode_List;
 // 可產生的執行緒數量
 volatile unsigned int m_ThreadNum = N;

 // 子執行緒的執行區塊,若沒有任務了會結束執行緒
 void threadProc()
 {
  while (true)
  {
   std::shared_ptr<ThreadNode> ThreadNode_Ptr = GetThreadNode();
   if (!ThreadNode_Ptr)
    break;
   ThreadNode_Ptr->toDo();
  }
 }

 // 若沒任務,會淢少一個 執行緒 的計數
 std::shared_ptr<ThreadNode> GetThreadNode()
 {
  std::shared_ptr<ThreadNode> Ret;

  {
   std::lock_guard<std::mutex> lock(m_ThreadLimit_mutex);
   if (m_ThreadNode_List.size() != 0)
   {
    Ret = m_ThreadNode_List.front();
    m_ThreadNode_List.pop_front();
   }
   else
   {
    ++m_ThreadNum; // 表示有一個執行緒會結束
    Ret = nullptr;
   }
  }
  return Ret;
 }

public:
 // Constructor
 ThreadLimit() {}
 // Destructor
 virtual ~ThreadLimit()
 {
  while (m_ThreadNum < N); // 等待所有子執行緒結束
 }

 // fn = 要在子執行緒中執行的函數
 // args = 要傳給 fn 使用的參數
 template<typename Fn, typename... Args>
 void Thread(Fn&& fn, Args&&... args)
 {
  std::function<void(void)> f
   = std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...);

  std::shared_ptr<ThreadNode> ThreadNode_Ptr(new ThreadNode(f));

  std::lock_guard<std::mutex> lock(m_ThreadLimit_mutex);
  m_ThreadNode_List.push_back(ThreadNode_Ptr); // 放入任務
  if (m_ThreadNum > 0)
  {
   --m_ThreadNum;
   std::thread m([this] {this->threadProc(); });
   m.detach();
  }
 }
};
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1034 | 人氣 3227 | 評價 1260 | 評價/貼文 1.22 | 送出評價 27 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/4/6 下午 04:29:29
/*
** 測試
*/

#include <random>
#include <iostream>


// 顯示 f1() 的參數值
void Show(int I)
{
 // 同步控制,免得多個 thread 同時搶著顯示資料
 static std::mutex _mutex;
 std::lock_guard<std::mutex> lock(_mutex);

 std::cout << "I is " << I << std::endl;
}

// 要丟給 ThreadLimit 執行的任務
void f1(int I)
{
 Show(I);

 static std::random_device rd;
 static std::default_random_engine gen =
  std::default_random_engine(rd());
 static std::uniform_int_distribution<int> dis(1, 5);

 // sleep 1∼5 秒
 std::this_thread::sleep_for(std::chrono::seconds(dis(gen)));
}


int main()
{
 ThreadLimit<5> TL; // 最多 5 個 thread 同時執行

 // 丟 20 個任務給 ThreadLimit 去執行
 for (int i = 1; i <= 10; ++i)
 {
  TL.Thread(f1, i); // 丟進 10 個一般函數

  // 丟進 10 個 std::function
  std::function<void(int)> f1_f(f1);
  TL.Thread(f1_f, i*100);
 }

 // 若出現錯誤訊息 mutex destroyed while busy,就加這行吧
 // std::this_thread::sleep_for(std::chrono::seconds(5)); // 等待所有子執行緒結束
 return 0;
}

作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1034 | 人氣 3227 | 評價 1260 | 評價/貼文 1.22 | 送出評價 27 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/4/8 下午 06:21:57
/*
** 優化速度及使用的資源
** 取消 template class 的宣告方式,
** 改由建構函數設定 thread 的最大使用數量
*/

#include <functional> // std::bind
#include <list>
#include <thread>
#include <mutex>


class ThreadLimit
{
 std::mutex m_ThreadLimit_mutex;

 // 待處理的任務
 std::list< std::function<void(void)> > m_ThreadNode_List;
 // 可產生的執行緒數量
 volatile unsigned int m_ThreadNum;

 // 產生的執行緒最大數量
 const unsigned int N;


 // 子執行緒的執行區塊,若沒有任務了會結束執行緒
 void threadProc()
 {
  std::function<void(void)> Func;
  while (true)
  {
   if (!GetThreadNode(Func))
    break;
   Func();
  }
 }

 // 若沒任務,會淢少一個 執行緒 的計數
 bool GetThreadNode(std::function<void(void)> &Func)
 {
  std::lock_guard<std::mutex> lock(m_ThreadLimit_mutex);
  if (m_ThreadNode_List.size() != 0)
  {
   Func = std::move(m_ThreadNode_List.front());
   m_ThreadNode_List.pop_front();
   return true;
  }
  else
  {
   ++m_ThreadNum; // 表示有一個執行緒會結束
   return false;
  }
 }

public:
 // Constructor
 // MaxN = 可產生的執行緒最大數量,須大於 0
 ThreadLimit(const unsigned int MaxN)
  :N(MaxN), m_ThreadNum(MaxN)
 {}
 // Destructor
 virtual ~ThreadLimit()
 {
  while (m_ThreadNum < N); // 等待所有子執行緒結束
 }

 // fn = 要在子執行緒中執行的函數
 // args = 要傳給 fn 使用的參數
 template<typename Fn, typename... Args>
 void Thread(Fn&& fn, Args&&... args)
 {
  std::function<void(void)> f
   = std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...);

  std::lock_guard<std::mutex> lock(m_ThreadLimit_mutex);
  m_ThreadNode_List.push_back(std::move(f)); // 放入任務
  if (m_ThreadNum > 0)
  {
   --m_ThreadNum;
   std::thread m([this] {this->threadProc(); });
   m.detach();
  }
 }
};
作者 : cxxlman(CxxlMan) C++優秀好手貼文超過1000則
[ 貼文 1034 | 人氣 3227 | 評價 1260 | 評價/貼文 1.22 | 送出評價 27 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2017/4/9 下午 04:56:22
使用 ThreadLimit 須要決定多少執行緒,總不能亂設一通吧,最好是以多少 CPU 多少核心為依據來設定,還好查到 std::thread::hardware_concurrency() 這個功能函數,最好上網了解一下,以下用優化後的 ThreadLimit 改寫測試程式

#include <random>
#include <iostream>

// 顯示 f1() 的參數值
void Show(int I)
{
 // 同步控制,免得多個 thread 同時搶著顯示資料
 static std::mutex _mutex;
 std::lock_guard<std::mutex> lock(_mutex);

 std::cout << "I is " << I << std::endl;
}

// 要丟給 ThreadLimit 執行的任務
void f1(int I)
{
 Show(I);

 static std::random_device rd;
 static std::default_random_engine gen =
  std::default_random_engine(rd());
 static std::uniform_int_distribution<int> dis(1, 5);

 // sleep 1∼5 秒
 std::this_thread::sleep_for(std::chrono::seconds(dis(gen)));
}


int main()
{
 // 執行緒最大數量為 硬體線程數 * 2
 ThreadLimit TL((std::thread::hardware_concurrency() == 0) ?
  8 : std::thread::hardware_concurrency() * 2);

 // 丟 20 個任務給 ThreadLimit 去執行
 for (int i = 1; i <= 10; ++i)
 {
  TL.Thread(f1, i); // 丟進 10 個一般函數

  // 丟進 10 個 std::function
  std::function<void(int)> f1_f(f1);
  TL.Thread(f1_f, i*100);
 }

 // 若出現錯誤訊息 mutex destroyed while busy,就加這行吧
 // std::this_thread::sleep_for(std::chrono::seconds(5)); // 等待所有子執行緒結束
 return 0;
}

 板主 : simula
 > C++ - 討論區
 - 最近熱門問答精華集
 - 全部歷史問答精華集
 - C++ - 知識庫
  ■ 全站最新Post列表
  ■ 我的文章收藏
  ■ 我最愛的作者
  ■ 全站文章收藏排行榜
  ■ 全站最愛作者排行榜
  ■  月熱門主題
  ■  季熱門主題
  ■  熱門主題Top 20
  ■  本區Post排行榜
  ■  本區評價排行榜
  ■  全站專家名人榜
  ■  全站Post排行榜
  ■  全站評價排行榜
  ■  全站人氣排行榜
 請輸入關鍵字 
  開始搜尋
 
Top 10
評價排行
C++
1 Raymond 13050 
2 青衫 4760 
3 simula 4690 
4 coco 4030 
5 白老鼠(Gary) 3670 
6 ozzy 2540 
7 Ben 2250 
8 Anderson 1960 
9 windblown 1650 
10 Kenny 1560 
C++
  專家等級 評價  
  一代宗師 10000  
  曠世奇才 5000  
  頂尖高手 3000  
  卓越專家 1500  
  優秀好手 750  
Microsoft Internet Explorer 6.0. Screen 1024x768 pixel. High Color (16 bit).
2000-2018 程式設計俱樂部 http://www.programmer-club.com.tw/
0.15625