Linux创建多个子线程并回收
創(chuàng)建子線程的邏輯相比子進(jìn)程要更容易理解一些,因?yàn)榫€程沒(méi)有像進(jìn)程那樣復(fù)制很多東西另起爐灶,子線程從傳入的開(kāi)始函數(shù)開(kāi)始運(yùn)行,但是難點(diǎn)在于傳入?yún)?shù)和回收時(shí)獲取退出狀態(tài),因?yàn)檫@兩個(gè)原本都是void *類(lèi)型的,而我們?cè)谑褂脮r(shí)就必須進(jìn)行轉(zhuǎn)換。先上代碼,然后再根據(jù)代碼進(jìn)行解釋:
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函數(shù)是我寫(xiě)的一個(gè)用于檢查返回值的工具函數(shù),mutex1是互斥量用于加鎖控制輸出(否則可能會(huì)很亂),子線程的工作很簡(jiǎn)單,就是輸出自己是第幾個(gè)線程。
-
其中比較關(guān)鍵的地方就是pthread_create的第四個(gè)參數(shù):向開(kāi)始函數(shù)傳參。這里我們可以看到把循環(huán)變量i轉(zhuǎn)換使用reinterpret_cast轉(zhuǎn)換成了void *類(lèi)型的,然后再在開(kāi)始函數(shù)func中使用reinterpret_cast函數(shù)將void *類(lèi)型轉(zhuǎn)換成了long類(lèi)型。
你可能覺(jué)得奇怪,為什么要把一個(gè)int類(lèi)型直接轉(zhuǎn)換成void *類(lèi)型,為什么不將其地址傳入呢?首先,要想清楚為什么使用void *類(lèi)型作為傳入?yún)?shù)的類(lèi)型:我認(rèn)為指針類(lèi)型比基本類(lèi)型更加廣泛,指針類(lèi)型可以保存基本類(lèi)型的值,也可以指向內(nèi)存,但是基本類(lèi)型是無(wú)法指向內(nèi)存的值的,因此使用空指針類(lèi)型靈活度更高,這里僅僅是這個(gè)場(chǎng)景下需要傳入一個(gè)整數(shù)而我們不想大費(fèi)周章在堆上分配內(nèi)存罷了,如果分配內(nèi)存的話顯然是需要指針的。
可不可以傳入int值的地址而不是將其本身傳入進(jìn)去呢?如果是單個(gè)線程應(yīng)該是沒(méi)有什么問(wèn)題,但是多個(gè)子線程下就有問(wèn)題了:因?yàn)樵摵瘮?shù)的棧空間是線程共享的,因此當(dāng)主控線程修改了循環(huán)變量的值以后子線程中的值也會(huì)被修改,這顯然不是我們想要的,如果還是感覺(jué)到無(wú)法理解的話可以自己手動(dòng)嘗試一下。
-
第二個(gè)問(wèn)題就是為什么要在func函數(shù)中使用reinterpret_cast將void *轉(zhuǎn)換為long類(lèi)型而不是int類(lèi)型,因?yàn)樵贑++里面轉(zhuǎn)換成int類(lèi)型會(huì)報(bào)錯(cuò)說(shuō)精度丟失(雖然C語(yǔ)言里面好像不會(huì),我看大家都在隨便轉(zhuǎn),感覺(jué)這個(gè)轉(zhuǎn)換太魔性了,還是C++規(guī)范一些),但是一般情況下long類(lèi)型和指針類(lèi)型的大小是差不多大的,轉(zhuǎn)換成 long類(lèi)型就不用擔(dān)心精度丟失了。
-
第三個(gè)問(wèn)題就是在使用pthread_join函數(shù)回收子線程的時(shí)候我們使用ret來(lái)獲取子線程退出狀態(tài),經(jīng)過(guò)測(cè)試發(fā)現(xiàn)在子線程的開(kāi)始函數(shù)的返回值就是最后的子線程退出狀態(tài)(當(dāng)然我們也可以使用pthread_exit函數(shù))
-
ret本身是void *類(lèi)型,pthread_join函數(shù)需要一個(gè)void **類(lèi)型,用來(lái)接收返回的void *類(lèi)型,在接收成功后我們?cè)俅螌⑵滢D(zhuǎn)換成long類(lèi)型。
運(yùn)行結(jié)果如下:
總結(jié)
以上是生活随笔為你收集整理的Linux创建多个子线程并回收的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 可以投屏的免费影视软件是什么?
- 下一篇: 下载英雄联盟怎么显示创建目录失败 请重新