一、使用 pthread_create 函數創建線程
pthread_create 是Linux下常見的創建線程的方法,它包含在 pthread 庫中。通過它我們可以在一個程序中創建多個線程來並行處理任務。
下面是一個簡單的示例,通過 pthread_create 創建兩個線程:
#include <iostream> #include <pthread.h> using namespace std; void* threadFunc(void* arg) { int num = *((int*) arg); cout << "Thread #" << num << ": hello world!" << endl; return NULL; } int main(int argc, char** argv) { pthread_t thread1, thread2; int thread1Num = 1, thread2Num = 2; pthread_create(&thread1, NULL, threadFunc, &thread1Num); pthread_create(&thread2, NULL, threadFunc, &thread2Num); pthread_join(thread1, NULL); pthread_join(thread2, NULL); cout << "Main thread exiting" << endl; return 0; }
在上面的代碼中,我們通過調用 pthread_create 函數來創建兩個線程 thread1 和 thread2。每個線程都調用 threadFunc 函數,在這個函數里我們輸出了一個簡單的 “hello world”。最後,我們通過調用 pthread_join 函數來等待兩個線程的結束,然後程序才能正常退出。
二、使用 std::thread 類創建線程
C++11 標準引入了 std::thread 類,可以方便地創建線程。相比於 pthread_create 函數,std::thread 更具有面向對象的特徵,更加易於使用。
下面是一個使用 std::thread 創建線程的示例:
#include <iostream> #include <thread> using namespace std; void threadFunc(int num) { cout << "Thread #" << num << ": hello world!" << endl; } int main(int argc, char** argv) { thread thread1(threadFunc, 1); thread thread2(threadFunc, 2); thread1.join(); thread2.join(); cout << "Main thread exiting" << endl; return 0; }
在上面的代碼中,我們通過使用 std::thread 類創建了兩個線程 thread1 和 thread2。和 pthread_create 不同的是,我們使用了類的構造函數來創建線程,也就是說,每個線程都是一個對象。在構造線程的時候,我們將要執行的函數和它的參數作為參數傳入線程構造函數。和 pthread_create 一樣,我們也需要調用 join() 函數等待線程結束。
三、線程同步與互斥
在多線程程序中,通常都需要處理線程同步和互斥的問題。如果多個線程同時訪問同一個數據,可能會導致數據出錯或者延時。因此,我們需要使用鎖來控制對共享資源的訪問,避免多個線程同時訪問同一個數據。
下面是一個使用 pthreads 庫來保護臨界段的示例:
#include <iostream> #include <pthread.h> using namespace std; int count = 0; pthread_mutex_t count_mutex; void* threadFunc(void* arg) { for (int i = 0; i < 5; i++) { pthread_mutex_lock(&count_mutex); count++; cout << "Thread #" << *((int*) arg) << " count = " << count << endl; pthread_mutex_unlock(&count_mutex); } return NULL; } int main(int argc, char** argv) { pthread_t thread1, thread2; int thread1Num = 1, thread2Num = 2; pthread_mutex_init(&count_mutex, NULL); pthread_create(&thread1, NULL, threadFunc, &thread1Num); pthread_create(&thread2, NULL, threadFunc, &thread2Num); pthread_join(thread1, NULL); pthread_join(thread2, NULL); pthread_mutex_destroy(&count_mutex); cout << "Main thread exiting" << endl; return 0; }
在上面的示例中,我們使用了 pthreads 庫的互斥量來保護全局變數 count。在 threadFunc 函數中,我們使用 pthread_mutex_lock 和 pthread_mutex_unlock 函數來加鎖和解鎖。這樣,當兩個線程同時訪問 count 變數時,一次只能有一個線程進行訪問,避免了數據錯亂。
除了使用互斥量外,C++11 中也提供了 std::mutex 來進行鎖操作。std::mutex 的用法和 pthread_mutex_t 是類似的,使用起來更加方便。
四、線程池
線程池是一種常見的多線程編程技術,通常用於處理大量並發請求。線程池中創建好多個線程,等待隊列中的任務。當任務來臨時,線程池中的線程會從隊列中取出任務進行處理,完成後再次回到隊列中等待新的任務。
下面是一個簡單的線程池實現:
#include <iostream> #include <thread> #include <queue> #include <mutex> #include <condition_variable> using namespace std; class ThreadPool { public: ThreadPool(int numThreads) { for (int i = 0; i < numThreads; i++) { threads.emplace_back([this] { for (;;) { function<void()> task; { unique_lock<mutex> lock(this->queueMutex); this->condition.wait(lock, [this] { return !this->tasks.empty() || this->stop; }); if (this->stop && this->tasks.empty()) { return; } task = std::move(this->tasks.front()); this->tasks.pop(); } task(); } }); } } ~ThreadPool() { { unique_lock<mutex> lock(queueMutex); stop = true; } condition.notify_all(); for (auto &thread : threads) { thread.join(); } } template <class Func, class... Args> auto enqueue(Func&& func, Args&&... args) -> future<typename result_of<Func(Args...)>::type> { using return_type = typename result_of<Func(Args...)>::type; auto task = make_shared<packaged_task<return_type()>>( bind(forward<Func>(func), forward<Args>(args)...) ); future<return_type> res = task->get_future(); { unique_lock<mutex> lock(queueMutex); tasks.emplace([task]() { (*task)(); }); } condition.notify_one(); return res; } private: vector<thread> threads; queue<function<void()>> tasks; mutex queueMutex; condition_variable condition; bool stop = false; }; void threadFunc(int num) { cout << "Thread #" << num << " hello world!" << endl; } int main(int argc, char** argv) { ThreadPool pool(4); pool.enqueue(threadFunc, 1); pool.enqueue(threadFunc, 2); pool.enqueue(threadFunc, 3); pool.enqueue(threadFunc, 4); return 0; }
在上面的示例中,我們實現了一個簡單的線程池。它包含了一個線程池的類 ThreadPool。它使用 std::vector 存儲所有線程,std::queue 存儲所有任務,std::mutex和 std::condition_variable 用於線程同步。
線程池的構造函數需要輸入線程數量 numThreads 作為參數,它會在構造函數中創建 numThreads 個線程。enqueue 函數可以添加新任務到隊列中,添加的任務將會在隊列中等待線程池中的線程去執行。
在 main 函數中,我們創建了一個線程池 pool,並且通過 pool.enqueue 函數添加了 4 個任務,並由線程池執行。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/240097.html