一、call_once 單例模式 Singleton?
大家可以先看這篇文章:https://zh.cppreference.com/w/cpp/thread/call_once
/*
std::call_once
void call_once( std::once_flag& flag, Callable&& f, Args&&... args );
*/
#include <iostream>
#include <mutex>
#include <thread>
std::once_flag flag1, flag2;
void simple_do_once() {
std::call_once(flag1, []() {
std::cout << "簡單樣例:調(diào)用一次\n";
});
}
void test1() {
std::thread st1(simple_do_once);
std::thread st2(simple_do_once);
std::thread st3(simple_do_once);
std::thread st4(simple_do_once);
st1.join();
st2.join();
st3.join();
st4.join();
}
void may_throw_function(bool do_throw) {
if (do_throw) {
std::cout << "拋出:call_once 會重試\n"; // 這會出現(xiàn)不止一次
throw std::exception();
}
std::cout << "沒有拋出,call_once 不會再重試\n"; // 保證一次
}
void do_once(bool do_throw) {
try {
std::call_once(flag2, may_throw_function, do_throw);
}
catch (...) {}
}
void test2() {
std::thread t1(do_once, true);
std::thread t2(do_once, true);
std::thread t3(do_once, false);
std::thread t4(do_once, true);
t1.join();
t2.join();
t3.join();
t4.join();
}
int main() {
test1();
test2();
return 0;
}
call_once 應(yīng)用在單例模式,以及關(guān)于單例模式我的往期文章推薦:C++ 設(shè)計模式----“對象性能“模式_愛編程的大丙 設(shè)計模式-CSDN博客https://heheda.blog.csdn.net/article/details/131466271
懶漢是一開始不會實例化,什么時候用就什么時候new,才會實例化
餓漢在一開始類加載的時候就已經(jīng)實例化,并且創(chuàng)建單例對象,以后只管用即可
--來自百度文庫
#include <iostream>
#include <thread>
#include <mutex>
#include <string>
// 日志類:在整個項目中,有提示信息或者有報錯信息,都通過這個類來打印
// 這些信息到日志文件,或者打印到屏幕上。顯然,全局只需要一個日志類的
// 對象就可以完成所有的打印操作了。不需要第二個類來操作,這個時候就可以
// 使用單例模式來設(shè)計它
std::once_flag onceFlag;
class Log {
public:
Log(const Log& log) = delete;
Log& operator=(const Log& log) = delete;
// static Log& getInstance() {
// static Log log; // 餓漢模式
// return log;
// }
static Log& getInstance() { // 懶漢模式
std::call_once(onceFlag, []() {
std::cout << "簡單樣例:調(diào)用一次\n";
log = new Log;
});
return *log;
}
void PrintLog(std::string msg) {
std::cout << __TIME__ << msg << std::endl;
}
private:
Log() {};
static Log* log;
};
Log* Log::log = nullptr;
void func() {
Log::getInstance().PrintLog("這是一個提示");
}
void print_error() {
Log::getInstance().PrintLog("發(fā)現(xiàn)一個錯誤");
}
void test() {
std::thread t1(print_error);
std::thread t2(print_error);
std::thread t3(func);
t1.join();
t2.join();
t3.join();
}
int main() {
test();
return 0;
}
二、condition_variable 與其使用場景
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <queue>
std::queue<int> queue;
std::condition_variable cond;
std::mutex mtx;
void Producer() {
for (int i = 0; i < 10; i++) {
{
std::unique_lock<std::mutex> locker(mtx);
queue.push(i);
cond.notify_one();
std::cout << "Producer : " << i << std::endl;
}
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
}
void Consumer() {
while (1) {
std::unique_lock<std::mutex> locker(mtx);
cond.wait(locker, []() {
return !queue.empty();
});
int value = queue.front();
queue.pop();
std::cout << "Consumer :" << value << std::endl;
}
}
int main() {
std::thread t1(Producer);
std::thread t2(Consumer);
t1.join();
t2.join();
return 0;
}
三、C++11 手撕線程池 + 單例模式(call_once)
- ThreadPool.h
#include <iostream>
#include <thread>
#include <mutex>
#include <string>
#include <condition_variable>
#include <queue>
#include <vector>
#include <functional>
std::once_flag onceFlag;
class ThreadPool {
private:
ThreadPool();
public:
ThreadPool(const ThreadPool& obj) = delete;
ThreadPool& operator=(const ThreadPool& obj) = delete;
static ThreadPool& getInstance();
~ThreadPool();
template<class F, class... Args>
void enqueue(F&& f, Args&&... args) {
std::function<void()> task =
std::bind(std::forward<F>(f), std::forward<Args>(args)...);
{
std::unique_lock<std::mutex> locker(mtx);
tasks.emplace(std::move(task));
}
cond.notify_one();
}
inline void setNum(int num) {
threadNum = num;
}
inline void printNum() {
std::cout << "線程數(shù)量為:" << threadNum << std::endl;
}
private:
static ThreadPool* pool;
std::vector<std::thread> threads;// 線程數(shù)組
std::queue<std::function<void()>> tasks;//任務(wù)隊列
std::mutex mtx;// 互斥鎖
std::condition_variable cond;//條件變量
bool stop;
int threadNum;// 線程數(shù)量
};
- ThreadPool.cpp
#include "ThreadPool.h"
#include <iostream>
ThreadPool* ThreadPool::pool = nullptr;
ThreadPool::ThreadPool() {
stop = false;
threadNum = 4;
for (int i = 0; i < threadNum; ++i) {
threads.emplace_back([this]() {
while (1) {
std::unique_lock<std::mutex> locker(mtx);
cond.wait(locker, [this]() {
return !tasks.empty() || stop;
});
if (stop && tasks.empty()) {
return;
}
std::function<void()> task(std::move(tasks.front()));
tasks.pop();
task();// 執(zhí)行這個任務(wù)
}
});
}
}
ThreadPool::~ThreadPool() {
{
std::unique_lock<std::mutex> locker(mtx);
stop = true;
}
cond.notify_all();
for (auto& t : threads) {
t.join();
}
}
ThreadPool& ThreadPool::getInstance() { // 懶漢模式
std::call_once(onceFlag, []() {
std::cout << "懶漢模式:調(diào)用一次" << std::endl;
pool = new ThreadPool();
});
return *pool;
}
- ?main.cpp
#include <iostream>
#include "ThreadPool.h"
#include <thread>
void addTask() {
ThreadPool& pool = ThreadPool::getInstance();
pool.setNum(8);
for (int i = 0; i < 10; ++i) {
pool.enqueue([i]() {
std::cout << "task : " << i << " is runing!" << std::endl;
std::this_thread::sleep_for(std::chrono::microseconds(10));
std::cout << "task : " << i << " is done!" << std::endl;
});
}
}
void test() {
std::thread t1(addTask);
std::thread t2(addTask);
std::thread t3(addTask);
t1.join();
t2.join();
t3.join();
}
int main() {
test();
return 0;
}
運行結(jié)果:文章來源:http://www.zghlxwxcb.cn/news/detail-818483.html
懶漢模式:調(diào)用一次
task : 0 is runing!
task : 0 is done!
task : 0 is runing!
task : 0 is done!
task : 1 is runing!
task : 1 is done!
task : 0 is runing!
task : 0 is done!
task : 1 is runing!
task : 1 is done!
task : 1 is runing!
task : 1 is done!
task : 2 is runing!
task : 2 is done!
task : 3 is runing!
task : 3 is done!
task : 2 is runing!
task : 2 is done!
task : 4 is runing!
task : 4 is done!
task : 3 is runing!
task : 3 is done!
task : 2 is runing!
task : 2 is done!
task : 3 is runing!
task : 3 is done!
task : 4 is runing!
task : 4 is done!
task : 5 is runing!
task : 5 is done!
task : 4 is runing!
task : 4 is done!
task : 5 is runing!
task : 5 is done!
task : 6 is runing!
task : 6 is done!
task : 7 is runing!
task : 7 is done!
task : 8 is runing!
task : 8 is done!
task : 9 is runing!
task : 9 is done!
task : 6 is runing!
task : 6 is done!
task : 7 is runing!
task : 7 is done!
task : 5 is runing!
task : 5 is done!
task : 6 is runing!
task : 6 is done!
task : 8 is runing!
task : 8 is done!
task : 9 is runing!
task : 9 is done!
task : 7 is runing!
task : 7 is done!
task : 8 is runing!
task : 8 is done!
task : 9 is runing!
D:\Work\vsproject\c++11\x64\Debug\c++11.exe (進程 32636)已退出,代碼為 0。
要在調(diào)試停止時自動關(guān)閉控制臺,請啟用“工具”->“選項”->“調(diào)試”->“調(diào)試停止時自動關(guān)閉控制臺”。
按任意鍵關(guān)閉此窗口. . .
- 關(guān)于智能指針的回顧,可以看我的往期文章了解一下喔!
獨占指針:unique_ptr 與 函數(shù)調(diào)用 筆記-CSDN博客https://heheda.blog.csdn.net/article/details/135841140計數(shù)指針:shared_ptr (共享指針)與函數(shù) 筆記-CSDN博客https://heheda.blog.csdn.net/article/details/135851596shared_ptr 與 unique_ptr 的轉(zhuǎn)換 筆記-CSDN博客https://heheda.blog.csdn.net/article/details/135853468weak_ptr 與 一個難發(fā)現(xiàn)的錯誤(循環(huán)依賴問題)筆記-CSDN博客https://heheda.blog.csdn.net/article/details/135854106文章來源地址http://www.zghlxwxcb.cn/news/detail-818483.html
到了這里,關(guān)于C++11手撕線程池 call_once 單例模式 Singleton / condition_variable 與其使用場景的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!