(第29章)UNIX系統編程手冊上之線程:介紹

一、實例代碼解釋

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()函數繼續對主線程堆棧中的數據進行操作,結果難以預測

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章