日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux 系统应用编程——线程基础

發布時間:2023/12/9 linux 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 系统应用编程——线程基础 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

傳送門:Linux多線程編程實例解析 .?

????????????????????linux多線程編程——同步與互斥 .

????

????? ?傳統多任務操作系統中一個可以獨立調度的任務(或稱之為順序執行流)是一個進程。每個程序加載到內存后只可以唯一地對應創建一個順序執行流,即傳統意義的進程。每個進程的全部系統資源是私有的,如虛擬地址空間,文件描述符和信號處理等等。使用多進程實現多任務應用時存在如下問題:

1)任務切換,即進程間上下文切換,系統開銷比較大。(虛擬地址空間以及task_struct 都需要切換)

2)多任務之間的協作比較麻煩,涉及進程間通訊。(因為不同的進程工作在不同的地址空間)

所以,為了提高系統的性能,許多操作系統規范里引入了輕量級進程的概念,也被稱為線程

?

一、線程基礎

????? 通常線程指的是共享相同地址空間的多個任務。線程最大的特點就是在同一個進程中創建的線程共享該進程的地址空間;但一個線程仍用task_struct 來描述,線程和進程都參與統一的調度。所以,多線程的好處便體現出來:

1)大大提高了任務切換的效率;因為各線程共享進程的地址空間,任務切換時只要切換task_struct 即可;

2)線程間通信比較方便;因為在同一塊地址空間,數據共享;

當然,共享地址空間也會成為線程的缺點,因為共享地址空間,如果其中一個線程出現錯誤(比如段錯誤),整個線程組都會崩掉!

???? Linux之所以稱呼其線程為LWP( Light Weight Process ),因為從內核實現的角度來說,它并沒有為線程單獨創建一個結構,而是繼承了很多進程的設計:

1)繼承了進程的結構體定義task_struct ;

2)沒有專門定義線程ID,復用了PID;

3)更沒有為線程定義特別的調度算法,而是沿用了原來對task_struct 的調度算法。

最新的Linux內核里線程已經替代原來的進程稱為調度的實際最小單位

原來的進程概念可以看成是多個線程的容器,稱之為線程組;即一個進程就是所有相關的線程構成的一個線程組。傳統的進程等價于單線程進程

每個線程組都有自己的標識符 tgid (數據類型為 pid_t ),其值等于該進程(線程組)中的第一個線程(group_leader)的PID。

?

1、創建線程

?pthread_create()函數描述如下:

所需頭文件#include <pthread.h>
函數原型

int pthread_create(pthread_t *thread,const pthread_attr_t *attr,

?????????????????????????????? void *(* routine)(void *), void *arg)

函數參數

thread :創建的線程

attr :指定線程的屬性,NULL表示使用缺省屬性

routine :線程執行的函數

arg :傳遞給線程執行的函數的參數

函數返回值

成功: 0

出錯: -1

1)這里routine 是回調函數(callback),其函數類型由內核來決定,這里我們將其地址傳給內核;這個函數并不是線程創建了就會執行,而是只有當其被調度到cpu上時才會被執行;具體回調函數的講解,移步Linux C 函數指針應用---回調函數 .;

2)arg 是線程執行函數的參數,這里我們將其地址穿進去,使用時需要先進行類型轉換,才能使用;如果參數不止一個,我們可以將其放入到結構體中;

?

2、pthread_join () 函數

其函數描述如下:

所需頭文件#include <pthread.h>
函數原型int thread_join(pthread_t thread, void? ** value_ptr)
函數參數

thread :要等待的線程

value_ptr :指針 *value_ptr 指向線程返回的參數

函數返回值

成功: 0

出錯: -1

這里,我們可以看到 value_ptr 是個二級指針,其是出參,存放的是線程返回參數的地址;

?

3、pthread_exit 函數

其函數描述如下:

所需頭文件#include <pthread.h>
函數原型int pthread_exit(void *value_ptr)
函數參數value_ptr :線程退出時返回的值
函數返回值

成功:0

出錯:-1

和進程中的exit() 、wait()一樣,這里pthread_join 與 pthread_exit 是工作在兩個線程之中;

?

下面看一個實例:

[cpp]?view plaincopy
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<string.h>??
  • #include?<pthread.h>??
  • ??
  • char?message[32]?=?"Hello?World!";??
  • void?*thread_function(void?*arg);??
  • ??
  • int?main()??
  • {??
  • ????pthread_t?a_thread;??
  • ????void?*thread_result;??
  • ??
  • ????if(pthread_create(&a_thread,NULL,thread_function,(void?*)message)?<?0)??
  • ????{??
  • ????????perror("fail?to?pthread_create");??
  • ????????exit(-1);??
  • ????}??
  • ??
  • ????printf("waiting?for?thread?to?finish\n");??
  • ????if(pthread_join(a_thread,&thread_result)?<?0)??
  • ????{??
  • ????????perror("fail?to?pthread_join");??
  • ????????exit(-1);??
  • ????}??
  • ??
  • ????printf("Message?is?now?%s\n",message);??
  • ????printf("thread_result?is?%s\n",(char?*)thread_result);??
  • ????return?0;??
  • }??
  • ??
  • void?*thread_function(void?*arg)??
  • {??
  • ????printf("thread_function?is?running,argument?is?%s\n",(char?*)arg);??
  • ????strcpy(message,"marked?by?thread");??
  • ????pthread_exit("Thank?you?for?the?cpu?time");??
  • }??
  • 編譯

    [cpp]?view plaincopy
  • fs@ubuntu:~/qiang/thread/0107$?gcc?-o?thread?thread.c?-lpthread??
  • fs@ubuntu:~/qiang/thread/0107$???
  • 線程通過第三方的線程庫來實現,所以這里要 -lpthread ,-l 是鏈接一個庫,這個庫是pthread;

    執行結果如下:

    [cpp]?view plaincopy
  • fs@ubuntu:~/qiang/thread/0107$?./thread???
  • waiting?for?thread?to?finish??
  • thread_function?is?running,argument?is?Hello?World!??
  • Message?is?now?marked?by?thread??
  • thread_result?is?Thank?you?for?the?cpu?time??
  • fs@ubuntu:~/qiang/thread/0107$???
  • 從這個程序,我們可以看到線程之間是如何通信的,線程之間通過二級指針來傳送參數的地址(這是進程所不具備的,因為他們的地址空間獨立),但兩個線程之間的通信,傳遞的數據的生命周期必須是靜態的。可以使全局變量、static修飾的數據、堆里面的數據;這個程序中的message就是一個全局變量。其中一個線程可以修改它,另一個線程得到它修改過后的message。

    ?

    二、線程的同步和互斥

    先來了解同步和互斥的基本概念:

    臨界資源:某些資源來說,其在同一時間只能被一段機器指令序列所占用。這些一次只能被一段指令序列所占用的資源就是所謂的臨界資源。

    臨界區:對于臨界資源的訪問,必須是互斥進行。也就是當臨界資源被一個指令序列占用時,另一個需要訪問相同臨界資源的指令序列就不能被執行。指令序列不能執行的實際意思就是其所在的進程/線程會被阻塞。所以我們定義程序內訪問臨界資源的代碼序列被稱為臨界區。

    互斥:是指同事只允許一個訪問者對臨界資源進行訪問,具有唯一性排它性。但互斥無法限制訪問這個對資源的訪問順序,即訪問時無序的。

    同步:是指在互斥的基礎上,通過其他機制實現訪問者對資源的有序訪問。

    ?

    1、線程間互斥

    引入互斥(mutual?? exlusion)鎖的目的是用來保證共享數據的完整性。

    互斥鎖主要用來保護臨界資源。每個臨界資源都有一個互斥鎖來保護,任何時刻最多只能有一個線程能訪問該資源;線程必須先獲得互斥鎖才能訪問臨界資源,訪問完資源后釋放該鎖。如果無法獲得鎖,線程會阻塞直到獲得鎖為止;

    通常,我們在臨界區前上鎖,臨界區后解鎖

    1)初始化互斥鎖函數

    所需頭文件#include <pthread.h>
    函數原型

    int pthread_mutex_init (pthread_mutex_t? *mutex,? pthread_mutexattr_t? *attr )

    //初始化互斥鎖

    函數參數

    mutex:互斥鎖

    attr :互斥鎖屬性 // NULL表示缺省屬性

    函數返回值

    成功:0

    出錯:-1

    2)申請互斥鎖函數

    所需頭文件#include <pthread.h>
    函數原型

    int pthread_mutex_lock(pthread_mutex_t *mutex)

    //申請互斥鎖

    函數參數

    mutex:互斥鎖

    函數返回值

    成功:0

    出錯:-1

    3)釋放互斥鎖函數

    所需頭文件#include <pthread.h>
    函數原型

    int pthread_mutex_unlock(pthread_mutex_t *mutex)

    //釋放互斥鎖

    函數參數

    mutex:互斥鎖

    函數返回值

    成功:0

    出錯:-1

    下面是一個實例:

    [cpp]?view plaincopy
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<string.h>??
  • #include?<pthread.h>??
  • #include?<unistd.h>??
  • //#define?_LOCK_??
  • ??
  • unsigned?int?value1,value2,count;??
  • pthread_mutex_t?mutex;??
  • void?*function(void?*arg);??
  • ??
  • int?main()??
  • {??
  • ????pthread_t?a_thread;??
  • ??
  • ????if(pthread_mutex_init(&mutex,NULL)?<?0)??
  • ????{??
  • ????????perror("fail?to?mutex_init");??
  • ????????exit(-1);??
  • ????}??
  • ??
  • ????if(pthread_create(&a_thread,NULL,function,NULL)?!=?0)??
  • ????{??
  • ????????perror("fail?to?pthread_create");??
  • ????????exit(-1);??
  • ????}??
  • ??
  • ????while(1)??
  • ????{??
  • ????????count++;??
  • #ifdef?_LOCK_??
  • ????????pthread_mutex_lock(&mutex);??
  • #endif??
  • ????????value1?=?count;??
  • ????????value2?=?count;??
  • #ifdef?_LOCK_??
  • ????????pthread_mutex_unlock(&mutex);??
  • #endif??
  • ????}??
  • ????return?0;??
  • }??
  • ??
  • void?*function(void?*arg)??
  • {??
  • ????while(1)??
  • ????{??
  • #ifdef?_LOCK_??
  • ????????pthread_mutex_lock(&mutex);??
  • #endif??
  • ????????if(value1?!=?value2)??
  • ????????{??
  • ????????????printf("count?=?%d,value1?=?%d,value2?=?%d\n",count,value1,value2);??
  • ????????????usleep(100000);??
  • ????????}??
  • #ifdef?_LOCK_??
  • ????????pthread_mutex_unlock(&mutex);??
  • #endif??
  • ????}??
  • ????return?NULL;??
  • }??
  • 執行結果如下:

    [cpp]?view plaincopy
  • fs@ubuntu:~/qiang/thread/0107$?./mutex??
  • ??
  • count?=?3368408,value1?=?3368408,value2?=?3368407??
  • count?=?44174760,value1?=?44174760,value2?=?44174759??
  • count?=?69313865,value1?=?69313865,value2?=?69313864??
  • count?=?139035309,value1?=?139035309,value2?=?139035308??
  • count?=?168803956,value1?=?168803956,value2?=?168803955??
  • count?=?192992611,value1?=?192992611,value2?=?192992610??
  • count?=?224279903,value1?=?224279903,value2?=?224279902??
  • count?=?259586793,value1?=?259586793,value2?=?259586792??
  • count?=?282057307,value1?=?282057307,value2?=?282057306??
  • count?=?321607823,value1?=?321607823,value2?=?321607822??
  • count?=?351629940,value1?=?351629940,value2?=?351629939??
  • count?=?374130545,value1?=?374130545,value2?=?374130544??
  • count?=?400727525,value1?=?400727525,value2?=?400727524??
  • count?=?440219988,value1?=?440219988,value2?=?440219987??
  • count?=?466069865,value1?=?466069865,value2?=?466069864??
  • count?=?500581241,value1?=?500581241,value2?=?500581240??
  • count?=?522649671,value1?=?522649671,value2?=?522649670??
  • count?=?569234325,value1?=?569234325,value2?=?569234324??
  • count?=?608139152,value1?=?608139152,value2?=?608139151??
  • count?=?639493957,value1?=?639493957,value2?=?639493956??
  • .....??
  • 我們可以看到,數據是不斷被打印的,說明 a 線程是可以訪問臨界資源的。

    我們把#define? _LOCK_前面的注釋去掉,這時就加上了互斥鎖,執行結果如下:

    [cpp]?view plaincopy
  • fs@ubuntu:~/qiang/thread/0107$?./mutex??
  • 此時,并沒有數據被打印,說明此時a線程中 value1 與 value 2 一直是相等的,說明主線程執行是,a線程并無法訪問臨界資源的。

    2、線程間同步

    同步(synchronization)?指的是多個任務(線程)按照約定的順序相互配合完成一件事情;

    線程間同步——P / V 操作

    信號量代表某一類資源,其值表示系統中該資源當前可用的數量。

    信號量是一個受保護的變量,只能通過三種操作來訪問:

    1)初始化

    2)P操作(申請資源)

    3)V操作(釋放資源)P(S)含義如下:

    [cpp]?view plaincopy
  • if?(信號量的值大于0)??
  • {??
  • ????請資源的任務繼續運行;??
  • ????信號量的值?減一;??
  • }??
  • else??
  • {??
  • ????請資源的任務阻塞;??
  • }??
  • V(S)含義如下:

    [cpp]?view plaincopy
  • if?(沒有任務在等待該資源)??
  • {??
  • ????信號量的值?加一;??
  • }??
  • else??
  • {??
  • ????喚醒第一個等待的任務,讓其繼續運行;??
  • }??
  • 1)、信號量初始化函數:

    所需頭文件#include <semaphore.h>
    函數原型

    int sem_int (sem_t *sem,int pshared,unsigned int value)

    //初始化信號量

    函數參數

    sem:初始化的信號量

    pshared:信號量共享的范圍(0:線程間使用 非0 :進程間使用)

    value :信號量初值

    函數返回值

    成功:0

    出錯:-1


    2)P操作

    所需頭文件#include <semaphore.h>
    函數原型

    int sem_wait (sem_t *sem) //P操作

    函數參數

    sem:信號量

    函數返回值

    成功:0

    出錯:-1

    3)V操作

    所需頭文件#include <semaphore.h>
    函數原型

    int sem_post(sem_t *sem) //V操作

    函數參數

    sem:信號量

    函數返回值

    成功:0

    出錯:-1


    下面是個實例:

    [cpp]?view plaincopy
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<string.h>??
  • #include?<pthread.h>??
  • #include?<semaphore.h>??
  • ??
  • char?buf[60];??
  • sem_t?sem;??
  • void?*function(void?*arg);??
  • ??
  • int?main(int?argc,?char?*argv[])??
  • {??
  • ????pthread_t?a_thread;??
  • ????void?*thread_result;??
  • ??
  • ????if(sem_init(&sem,0,0)?!=?0)??
  • ????{??
  • ????????perror("fail?to?sem_init");??
  • ????????exit(-1);??
  • ????}??
  • ??
  • ????if(pthread_create(&a_thread,NULL,function,NULL)?!=?0)??
  • ????{??
  • ????????perror("fail?to?pthread_create");??
  • ????????exit(-1);??
  • ????}??
  • ??
  • ????printf("input?'quit'?to?exit\n");??
  • ????do????
  • ????{??
  • ????????fgets(buf,60,stdin);??
  • ????????sem_post(&sem);??
  • ????}??
  • ????while(strncmp(buf,"quit",4)?!=?0);??
  • ??????
  • ????return?0;??
  • }??
  • ??
  • void?*function(void?*arg)??
  • {??
  • ????while(1)??
  • ????{??
  • ????????sem_wait(&sem);??
  • ????????printf("you?enter?%d?characters\n",strlen(buf)?-?1);??
  • ????}??
  • }??
  • 執行結果如下:

    [cpp]?view plaincopy
  • fs@ubuntu:~/qiang/thread/0107$?./sem???
  • input?'quit'?to?exit??
  • xiao??
  • you?enter?4?characters??
  • zhi??
  • you?enter?3?characters??
  • qiang??
  • you?enter?5?characters??
  • quit??
  • fs@ubuntu:~/qiang/thread/0107$???
  • 我們可以看到兩個線程是同步的。

    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的Linux 系统应用编程——线程基础的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 免费看黄网址 | 国产吞精囗交免费视频网站 | 国产探花一区二区 | 中文在线免费观看 | 寂寞少妇让水电工爽hd | 91九色porny视频 | 天堂网中文在线 | 永久免费未满蜜桃 | 国产日韩在线免费观看 | ass极品水嫩小美女ass | 欧美粗大猛烈 | 精品视频中文字幕 | 久色88| 天天色网站 | www.五月天婷婷 | 亚洲性图第一页 | 色99999| 欧美成人吸奶水做爰 | 日韩在线欧美 | 国产一区免费在线 | 日韩在线www | 在线黄色av网站 | 中文字幕不卡在线播放 | 亚洲一区二区在线播放 | 成年人黄色大片 | 成人精品影视 | 欧美一级少妇 | 日韩精品免费一区二区三区 | 久久精品国产99国产 | 成人香蕉视频 | 男人扒女人添高潮视频 | 天天夜夜人人 | 超碰超碰超碰超碰超碰 | 你懂的国产在线 | 人人澡超碰碰97碰碰碰 | 午夜黄色福利 | 成人免费毛片高清视频 | 午夜电影一区二区 | 国产日韩精品在线 | 人人免费操 | 中文字幕日韩经典 | 全黄性高潮 | 欧美青青草| 精品国产乱码久久久久久1区二区 | 久久最新精品 | 老司机午夜免费精品视频 | 亚洲综合第一页 | 日韩第一页在线观看 | 国内av在线| 精品无码一区二区三区免费 | 国产国产乱老熟女视频网站97 | av天堂一区 | 天堂中文av| 一卡二卡国产 | 青青一区二区 | 久久中文字 | 污污网站在线 | 国产精一区 | 黄色片子一级 | 欧美自拍视频在线观看 | 天堂视频在线免费观看 | 激情瑟瑟 | 少妇全黄性生交片 | 黄色美女免费网站 | 国产综合视频在线 | 国产小视频在线观看 | 日本xxxx18高清hd| 日本手机看片 | 91av麻豆| 五月婷婷俺也去 | 99精品乱码国产在线观看 | 日韩亚洲第一页 | 一级视频黄色 | 欧美一区二区三区四区视频 | 久久精品国产99精品国产亚洲性色 | 欧美青草视频 | 少妇激情一区二区三区视频 | 天堂最新资源在线 | 亚洲精品乱码久久久久久自慰 | 国产激情二区 | 亚洲乱码一区 | 亚洲熟妇国产熟妇肥婆 | 亚洲婷婷丁香 | 欧美性三级 | 哪里有毛片看 | 91精品国产91久久久久久久久久久久 | 国产精品天美传媒沈樵 | 日韩av线 | 久久久久亚洲AV成人无在 | 男男成人高潮片免费网站 | 欧美一区二区三区免费在线观看 | 色多多黄色| 亚洲精品观看 | 亚洲天堂三级 | 日韩av免费在线看 | 成人免费淫片aa视频免费 | 九九热最新 | 91视频综合网 | 国产毛片久久久久久 |