創建子線程的邏輯相比子進程要更容易理解一些,因為線程沒有像進程那樣復制很多東西另起爐灶,子線程從傳入的開始函數開始運行,但是難點在于傳入參數和回收時獲取退出狀態,因為這兩個原本都是void *
類型的,而我們在使用時就必須進行轉換。先上代碼,然后再根據代碼進行解釋:
void pthread_check(int ret, const std::string msg = "error", int default_ret = 0);using std::cout;
using std::endl;
namespace {pthread_mutex_t mutex1;
}void *func(void * argc) {
// int idx = *reinterpret_cast<int *>(argc);int idx = reinterpret_cast<long>(argc);pthread_mutex_lock(&mutex1);cout << "I am thread " << idx << "\n";pthread_mutex_unlock(&mutex1);//pthread_exit(argc);return argc;
}void create_multi_thread() {pthread_mutex_init(&mutex1, nullptr);constexpr int N = 5;pthread_t tid[N];void *ret;for (int i = 0; i < N; ++i) {pthread_check(pthread_create(&tid[i], nullptr, func, reinterpret_cast<void *>(i)));}pthread_mutex_lock(&mutex1);cout << "I am thread 5" << "\n";pthread_mutex_unlock(&mutex1);for (int i = 0; i < N; ++i) {pthread_join(tid[i], &ret);pthread_mutex_lock(&mutex1);cout << "thread " << i << " exits with status : " << reinterpret_cast<long>(ret) << "\n";pthread_mutex_unlock(&mutex1);}pthread_exit(0);
}
其中pthread_check
函數是我寫的一個用于檢查返回值的工具函數,mutex1
是互斥量用于加鎖控制輸出(否則可能會很亂),子線程的工作很簡單,就是輸出自己是第幾個線程。
-
其中比較關鍵的地方就是
pthread_create
的第四個參數:向開始函數傳參。這里我們可以看到把循環變量i
轉換使用reinterpret_cast
轉換成了void *
類型的,然后再在開始函數func
中使用reinterpret_cast
函數將void *
類型轉換成了long
類型。你可能覺得奇怪,為什么要把一個
int
類型直接轉換成void *
類型,為什么不將其地址傳入呢?首先,要想清楚為什么使用void *
類型作為傳入參數的類型:我認為指針類型比基本類型更加廣泛,指針類型可以保存基本類型的值,也可以指向內存,但是基本類型是無法指向內存的值的,因此使用空指針類型靈活度更高,這里僅僅是這個場景下需要傳入一個整數而我們不想大費周章在堆上分配內存罷了,如果分配內存的話顯然是需要指針的。可不可以傳入
int
值的地址而不是將其本身傳入進去呢?如果是單個線程應該是沒有什么問題,但是多個子線程下就有問題了:因為該函數的棧空間是線程共享的,因此當主控線程修改了循環變量的值以后子線程中的值也會被修改,這顯然不是我們想要的,如果還是感覺到無法理解的話可以自己手動嘗試一下。 -
第二個問題就是為什么要在
func
函數中使用reinterpret_cast
將void *
轉換為long
類型而不是int
類型,因為在C++里面轉換成int
類型會報錯說精度丟失(雖然C語言里面好像不會,我看大家都在隨便轉,感覺這個轉換太魔性了,還是C++規范一些),但是一般情況下long
類型和指針類型的大小是差不多大的,轉換成long
類型就不用擔心精度丟失了。 -
第三個問題就是在使用
pthread_join
函數回收子線程的時候我們使用ret
來獲取子線程退出狀態,經過測試發現在子線程的開始函數的返回值就是最后的子線程退出狀態(當然我們也可以使用pthread_exit
函數) -
ret
本身是void *
類型,pthread_join
函數需要一個void **
類型,用來接收返回的void *
類型,在接收成功后我們再次將其轉換成long
類型。
運行結果如下: