文章目錄
- 九、多線程
- 3. C++11中的多線程
- 4. 線程的簡單封裝
- 未完待續
九、多線程
3. C++11中的多線程
Linux中是根據多線程庫來實現多線程的,C++11也有自己的多線程,那它的多線程又是怎樣的?我們來使用一些C++11的多線程。
Makefile:
testThread: testThread.ccg++ -o $@ $^ -std=c++11
.PHONY: clean
clean:rm -f testThread
testThread.cc
#include <iostream>
#include <thread>
#include <unistd.h>
using namespace std;void threadrun(int num)
{while (num){cout << "I am thread, num : " << num << endl;sleep(1);--num;}
}int main()
{thread t1(threadrun, 10);while (true){cout << "I am main thread" << endl;sleep(1);}t1.join();return 0;
}
編譯看看:
我們發現有問題(也可能是其他問題),這是怎么回事呢?其實是 C++11的多線程本質上是對原生線程的封裝。所以同樣需要鏈接 phread 動態庫。
Makefile:
testThread: testThread.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY: clean
clean:rm -f testThread
我們再試試:
確實大部分其編程語言的多線程都是對原生線程的封裝,原因是為了可移植性。
我們在進程部分學過 非阻塞等待 ,進程在等待子進程退出時,可以執行其他任務,在線程這里,同樣有這樣的技術,叫做線程分離。我們要是不關注線程的結果,只需要線程把自己的任務完成,這種情況就可以將線程進行分離。
Makefile:
testThread: testThread.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY: clean
clean:rm -f testThread
testThread.cc:
#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>
using namespace std;void* threadrun(void* args)
{string str = (const char*)args;int cnt = 5;while (true){if (!(cnt--)) break;cout << "I am a new thread " << endl;sleep(1);}
}int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadrun, (void*)"thread1");// 線程分離pthread_detach(tid);while (true){cout << "I am the main thread " << endl;sleep(1);}return 0;
}
默認情況下,新創建的線程是joinable的,線程退出后,需要對其進行pthread_join操作,否則無法釋放資源,從而造成系統泄漏。
如果不關心線程的返回值,join是一種負擔,這個時候,我們可以告訴系統,當線程退出時,自動釋放線程資源。
joinable和分離是沖突的,一個線程不能既是joinable又是分離的。如果將線程分離了又對其join,就會出錯。
線程分離底層依舊是屬于進程,沒有分開,線程分離只是一種狀態,唯一的區別就是主線程不需要等待新線程。
4. 線程的簡單封裝
Makefile:
testThread: testThread.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY: clean
clean:rm -f testThread
Thread.hpp:
#ifndef __THREAD_HPP__
#define __THREAD_HPP__#include <iostream>
#include <pthread.h>
#include <string>
#include <functional>
#include <unistd.h>// 線程命名空間
namespace ThreadModule
{// 線程函數模板template<typename T>using func_t = std::function<void(T&)>;// 線程模板template<typename T>class Thread{public:Thread(func_t<T> func, T data, const std::string& name = "none-name"):_func(func),_data(data),_threadname(name),_stop(true){}void Excute(){_func(_data);}static void* threadtoutine(void* args){Thread<T>* self = (Thread<T>*)args;self->Excute();return nullptr;}// 啟動線程bool Start(){int n = pthread_create(&_tid, nullptr, threadtoutine, this);if (n == 0){_stop = false;return true;}else return false;}// 分離線程void Detach(){if (!_stop){pthread_detach(_tid);}}// 等待線程結束void Join(){if (!_stop){pthread_join(_tid, nullptr);}}std::string name(){return _threadname;}// 停止線程void Stop(){_stop = true;}~Thread(){}private:pthread_t _tid;std::string _threadname;T _data;func_t<T> _func;bool _stop;};
}#endif
testThread.cc:
#include <iostream>
#include <vector>
#include "Thread.hpp"
using namespace ThreadModule;const int num = 10;// 線程執行的任務
void print(int& cnt)
{while (cnt){std::cout << "hello I am myself thread, cnt: " << cnt-- << std::endl;sleep(1);}
}int main()
{// 創建多線程std::vector<Thread<int>> threads;// 創建num個線程,每個線程執行print函數for (int i = 0; i < num; ++i){std::string name = "thread-" + std::to_string(i + 1);threads.emplace_back(print, 10, name);}// 啟動線程for (auto& thread : threads){thread.Start();}// 等待線程結束for (auto& thread : threads){thread.Join();std::cout << "wait thread done, thread name: " << thread.name() << std::endl;}return 0;
}
結果: