一、使用 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
微信掃一掃
支付寶掃一掃