一、實例代碼解釋
29-1:使用Pthreads的簡單程序
/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2019. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation, either version 3 or (at your option) any *
* later version. This program is distributed without any warranty. See *
* the file COPYING.gpl-v3 for details. *
\*************************************************************************/
/* Listing 29-1 */
/* simple_thread.c
A simple POSIX threads example: create a thread, and then join with it.
*/
#include <pthread.h>
#include "tlpi_hdr.h"
static void * threadFunc(void *arg)
{
char *s = (char *) arg;
printf("%s", s);
return (void *) strlen(s);
}
int main(int argc, char *argv[])
{
pthread_t t1;
void *res;
int s;
/*
(1)pthread_creat()函數創建一條新線程,線程函數是threadFunc(),其函數的形參是“Hello word\n”;
(2)線程threadFunc()函數在執行return的時候就會終止線程;
*/
s = pthread_create(&t1, NULL, threadFunc, "Hello world\n");
if (s != 0)
errExitEN(s, "pthread_create");
/*
(1)pthread_join()函數必須連接已終止的可joinable的線程。
即在調用pthread_join()函數時,thread_creat()線程已經終止了。
(2)默認情況下,線程是可連接的joinable的,即:當線程退出時,其他線程可以通過調用pthread_join()函數獲取其返回狀態
*/
printf("Message from main()\n");
s = pthread_join(t1, &res);
if (s != 0)
errExitEN(s, "pthread_join");
printf("Thread returned %ld\n", (long) res);
exit(EXIT_SUCCESS);
}
/*
1.函數原型:
#include <pthread.h>
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,
(void*)(*start)(void*),void *arg);
int pthread_join(pthread_t thread, void **retval);
1.線程終止的方式
(1)線程start函數執行return語句並返回指定值
(2)線程調用pthread_exit(),注:若主線程調用了pthread_exit()函數,
而非調用exit()或執行return函數,那麼其他線程將繼續運行
(3)調用pthread_cancel()取消線程
(4)任意線程調用了exit()函數,或者主線程執行了return語句(在main()函數中),都會導致進程中的所有線程立即終止
注:exit()函數和pthread_exit()函數不一樣
2.該代碼中有兩個線程:main()函數的主線程,threadFunc函數的線程
*/
輸出:
29-2:使用分離屬性創建線程
/*************************************************************************\
* Copyright (C) Michael Kerrisk, 2019. *
* *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation, either version 3 or (at your option) any *
* later version. This program is distributed without any warranty. See *
* the file COPYING.gpl-v3 for details. *
\*************************************************************************/
/* Listing 29-2 */
/* detached_attrib.c
An example of the use of POSIX thread attributes (pthread_attr_t):
creating a detached thread.
*/
#include <pthread.h>
#include "tlpi_hdr.h"
static void *
threadFunc(void *x)
{
return x;
}
int
main(int argc, char *argv[])
{
pthread_t thr;
pthread_attr_t attr;
int s;
s = pthread_attr_init(&attr); /* Assigns default values */
if (s != 0)
errExitEN(s, "pthread_attr_init");
s = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (s != 0)
errExitEN(s, "pthread_attr_setdetachstate");
s = pthread_create(&thr, &attr, threadFunc, (void *) 1);
if (s != 0)
errExitEN(s, "pthread_create");
s = pthread_attr_destroy(&attr); /* No longer needed */
if (s != 0)
errExitEN(s, "pthread_attr_destroy");
s = pthread_join(thr, NULL);
if (s != 0)
errExitEN(s, "pthread_join failed as expected");
exit(EXIT_SUCCESS);
}
/*
1.pthread_creat()中pthread_attr_t的attr參數可以在創建線程時,指定新線程的
屬性,屬性包括:線程棧的位置和大小、線程調度策略和優先級,以及線程是否處於可連接
或分離狀態
2.函數thread_join()會等待由thread標識的線程終止,若線程已終止,thread_join()會
立即返回
3.可連接joinable的線程與分離detached的線程的區別是:
可連接的線程,當線程退出時,其他線程可以通過調用pthread_join獲取其返回狀態;
線程之間的關係是對等的,進程中的任意線程均可以調用pthread_join()與該進程
中的任何其他線程連接起來;
分離的線程是系統在線程終止時,能夠自動清理並移除;
4.pthread_detach()與29-2設置分離detached的線程是不同的,原因是:
使用過pthread_detach()分離線程,就不能再使用pthread_join()來獲取其狀態,也無法使其重返“可連接”狀態;
而29-2的則可以;
*/
原書上的解釋:
二、習題
29-1習題
若一線程執行了如下的代碼。可能會產生什麼結果?
pthread_join(pthread_self(),NULL)
在Linux上編寫一個程序,觀察一下實際會發生什麼情況。假設代碼中有一變量tid,其中包含了某個線程ID,在自身發起pthread_join(tid,NULL)調用時,要避免造成與上述語句相同的後果,該線程應該採取何種措施?
答案:
可能會有兩種結果:線程死鎖。當試圖加入自己時遭到阻塞,或者調用pthread_join()失敗,,返回錯誤爲EDEADLK,在Linux中,會發生後一種行爲。
若向pthread_join()傳入一個之前已經連接joining過的線程ID,將會導致無法預知的行爲。eg:相同的線程ID在參與一次連接後恰好爲另一新建線程所重用,再度連接的可能就是這個新線程。
在tid中給定一個線程ID,可使用如下代碼來阻止這種不測事件。
函數原型
#include <pthread.h>
int pthread_equal(pthread_t t1, pthread_t t2);
/*
pthread_eaual()是判斷調用線程的線程ID與保存在變量t1中的線程ID是否一致;
若一致,返回非0;若不一致,返回0;
*/
if (!pthread_equal(tid,pthread_self())
pthread_join(tid,NULL);
29-2習題
除了缺少錯誤檢查,以及對各種變量和結構的聲明外,下列程序還有什麼問題?
static void * threadFunc(void *arg)
{
struct someStruct *pbuf=(struct someStruct *)arg;
/*Do some work with structure pointed to by 'pbuf'*/
}
int main(int argc, char *argv[])
{
struct someStruct buf;
pthread_creat(&thr,NULL,threadFunc,(void *)&buf);
pthred_exit(NULL);
}
主線程終止後,threadFunc()函數繼續對主線程堆棧中的數據進行操作,結果難以預測