Linux系統編程——多線程

線程是獨立調度的基本單位。一個進程可以有一個或者多個線程,線程之間共享進程資源。

線程分類

按調度者分爲:

  • 用戶級線程(User Level Thread,ULT)

    解決上下文切換問題,調度算法和過程由用戶決定
    存在於用戶空間
    線程創建、撤銷以及線程之間的同步、通信無需系統調用來實現
    同一進程的線程切換不需要內核支持
    調度以進程爲單位
    

    優點:

    線程切換不需要到內核空間,節省內核空間
    調度算法可以進程專用,亦或用戶程序指定
    用戶線程實現與操作系統無關
    

    缺點:

    同一進程一個線程執行系統調用阻塞就導致進程阻塞
    一個進程只能在一個CPU上獲得執行,無法發揮SMP(對稱多處理器)的優勢
    
  • 核心級線程(kernel Supported threads,KST)

    不同進程的線程按照同一相對優先調度算法調度,發揮SMP優勢
    線程創建撤銷、以及切換等等通過系統調用陷入內核由內核響應程序處理
    調度以線程爲基本單位
    

    優點:

    在SMP情況下,內核可以調度同一進程通中的多個線程併發工作
    同一線程的一個線程阻塞,其他線程依然可以運行
    

​ 缺點:

      主要是程序在內核態和用戶態之間切換帶來的開銷

線程相關API

線程的創建:

pthread_create - create a new thread  //創建一個新線程

//頭文件
#include <pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);
thread —— 新線程TID(Thread id 類似進程的pid)
attr  —— 線程屬性,爲NULL創建一個標準線程
start_routine —— 線程入口函數
arg —— 線程入口參數

RETURN VALUE
  成功返回0; 錯誤返回errno, and the contents of *thread are undefined.

errno —— 一個全局變量,存放各種API執行失敗的原因

線程的退出:

  • 線程入口函數調用return語句並指定返回值
  • 線程調用pthread_exit()
  • 調用pthread_cancel取消線程
  • 任意線程調用exit()或者main線程調用了return,都將導致所有線程退出
pthread_exit - terminate calling thread 

#include <pthread.h>

void pthread_exit(void *retval);  //線程退出
retval —— 退出值

Compile and link with -pthread.//編譯要鏈接pthread庫

線程取消:

pthread_cancel - send a cancellation request to a thread //發送取消線程請求

#include <pthread.h>

int pthread_cancel(pthread_t thread);  //取消線程

RETURN VALUE
    成功 pthread_cancel() 返回 0; 失敗, 返回非零 error number.

獲取線程的退出值

pthread_join - join with a terminated thread

#include <pthread.h>  

int pthread_join(pthread_t thread, void **retval); //獲取線程退出值
thread —— 線程TID
retval —— 線程退出值

RETURN VALUE
    成功 pthread_join()  0; 失敗返回 error  number.

獲取自身TID:

pthread_self - obtain ID of the calling thread

#include <pthread.h>

pthread_t pthread_self(void);

RETURN VALUE
	成功返回線程TID,不存在失敗

創建標準線程:

/***************************************************************************************************
  * @file:     xxx.c
  * @author:   guangjieMVP
  * @github:  
  * @version:  v1.0.0
  * @date:     2020-xx-xx
  * @brief:               
*****************************************************************************************************/
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>

int retval = 0xff;
void *thread1_entry(void *arg)
{
    static int cnt = 0;
    
    while (1)
    {
        printf("Linux %d\r\n", cnt++);
        if(cnt >= 10)
        {
            cnt = 0;
            pthread_exit(&retval);
        }
        sleep(2);
    }
}

void *thread2_entry(void *arg)
{
    while (1)
    {
        printf("ubuntu\r\n");
        sleep(3);
    }
}

int main(int argc, char **argv)
{
    pthread_t thread1;
    pthread_t thread2;

    pthread_create(&thread1, NULL, thread1_entry, NULL);  //attr爲NULL——使用默認屬性創建thread
    pthread_create(&thread2, NULL, thread2_entry, NULL);
    
    static int maincnt = 0;
    unsigned char flag = 0;
    while(1)
    {
        printf("main thread %d\r\n", maincnt++);
        if(maincnt >= 10 && !flag)
        {
            maincnt = 0;
            flag = 1;
            pthread_cancel(thread2);
        }
        sleep(1);
    }
    
    return 0;
}

編譯執行:

gcc pthread_create.c -o pthread_create -lpthread  //編譯程序

//-lpthread —— 鏈接pthread線程庫
    
./pthread_create  //執行程序

線程分離與接合

默認情況下線程是可連接狀態——線程退出時不會釋放資源,其他線程可以通過pthread_join()獲取其退出值

不關心線程返回狀態可以把線程設置爲可分離的——線程結束系統自動釋放並清理資源,線程必定不會成爲殭屍線程s

pthread_detach - detach a thread  //設置線程屬性爲分離

#include <pthread.h>

int pthread_detach(pthread_t thread);
thread —— 線程ID

RETURN VALUE
    成功返回0; 失敗, 返回errno

線程屬性

線程屬性包含屬性:線程棧的大小和位置、調度策略、優先級等以及線程是分離還是可連接
pthread_attr_init, pthread_attr_destroy - initialize and destroy thread attributes object   //初始化或者銷燬銷燬線程屬性
頭文件
#include <pthread.h>

int pthread_attr_init(pthread_attr_t *attr); //初始化線程屬性
int pthread_attr_destroy(pthread_attr_t *attr);//銷燬線程屬性
attr —— 線程屬性

pthread_attr_setdetachstate,  pthread_attr_getdetach‐state - 設置or獲取線程的分離狀態

#include <pthread.h>

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
attr —— 線程屬性
detachstate —— 分離狀態:
      PTHREAD_CREATE_DETACHED — 分離狀態
      PTHREAD_CREATE_JOINABLE — 可連接狀態

RETURN VALUE
   成功返回0; 失敗返回非0的errno

分離屬性創建線程:

    int ret;
    pthread_attr_t attr; //定義線程屬性變量
    
    ret = pthread_attr_init(&attr); //初始化線程屬性變量
    if(ret != 0)
    {
        printf("faild to init attr\r\n");
        exit(0);
    }
    
    ret = pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);//設置線程爲分離狀態
    if(ret != 0)
    {
        printf("faild to setdetach\r\n");
        exit(0);
    }
    pthread_create(&thread1, &attr, thread1_entry, NULL); //使用attr屬性創建線程
    pthread_create(&thread2, &attr, thread2_entry, NULL);

設置以及獲取線程調度策略

pthread_attr_setschedpolicy, pthread_attr_getschedpolicy - 獲取or設置線程調度策略

#include <pthread.h>

int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); //設置線程調度策略
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
attr —— 線程屬性

policy —— 調度策略
      SCHED_FIFO —— 以先進先出的派對方式調度,處於就緒就會被立即放入所在優先級隊列隊尾
                    被更高優先級搶佔後會被放入所在優先級隊列隊頭,高優先級運行結束其立即
                    恢復運行
                    可以調用sched_yield()主動讓出CPU
      SCHED_RR   —— 以輪轉的方式調度, 線程會被分配一定的時間片,
                    時間片耗盡會被放入所在優先級隊列的隊尾
      SCHED_OTHER —— 非實時調度的普通線程,靜態優先級必須設置爲0,使用Linux系統默認的調度策略——按照動態優先級調度

RETURN VALUE
       On success, these functions return 0; on error,  they  return  a  nonzero error number.


獲取、設置線程調度策略以及靜態優先級


 pthread_attr_setschedparam,  pthread_attr_getschedparam  - 設置、獲取靜態線程優先級

#include <pthread.h>
       
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
//attr —— 線程屬性
//param —— 線程靜態優先級

RETURN VALUE
    On  success,  these  functions  return  0;  on error, they return a nonzero error number.

獲取、設置線程調度策略以及靜態優先級

pthread_setschedparam,  pthread_getschedparam - 設置or獲取線程調度策略以及靜態優先級

#include <pthread.h>

int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param); //設置調度策略以及靜態優先級
int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param);
//thread —— 線程TID
//policy —— 調度策略
//param —— 靜態優先級

 struct sched_param {
     int sched_priority;     /* Scheduling priority */
};

獲取、設置線程動態優先級

nice - change process priority

 #include <unistd.h>

int nice(int inc);

線程棧

線程創建後都有一個線程棧,缺省情況下大小固定。線程棧大小可以改變

#include <pthread.h>

int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize);
attr —— 線程屬性結構體
stackaddr —— 線程棧地址
stacksize —— 線程棧大小

RETURN VALUE
    成功返回0;失敗返回非零錯誤編碼
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章