Linux上線程開發API概要(線程)

進程與線程
??????典型的UNIX/Linux進程可以看成只有一個控制線程:一個進程在同一時刻只做一件事情。有了多個控制線程后,在程序設計時可以把進程設計成在同一時刻做不止一件事,每個線程各自處理獨立的任務。

?????? 進程是程序執行時的一個實例,是擔當分配系統資源(CPU時間、內存等)的基本單位。在面向線程設計的系統中,進程本身不是基本運行單位,而是線程的容器。程序本身只是指令、數據及其組織形式的描述,進程才是程序(那些指令和數據)的真正運行實例。
?????? “進程——資源分配的最小單位,線程——程序執行的最小單位”
??????一個進程至少包含一個線程,進程是運行的程序,程序是靜態的概念,進程是動態的概念。
??????進程有獨立的地址空間,一個進程崩潰后,在保護模式下不會對其它進程產生影響,而線程只是一個進程中的不同執行路徑。線程有自己的堆棧和局部變量,但線程沒有單獨的地址空間,一個線程死掉就等于整個進程死掉,所以多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對于一些要求同時進行并且又要共享某些變量的并發操作,可以用線程,也可以用進程間的通信。
使用線程的理由
??????從上面我們知道了進程與線程的區別,其實這些區別也就是我們使用線程的理由。總的來說就是:進程有獨立的地址空間,線程沒有單獨的地址空間(同一進程內的線程共享進程的地址空間)。

??????使用多線程的理由之一是和進程相比,它是一種非常"節儉"的多任務操作方式。我們知道,在Linux系統下,啟動一個新的進程必須分配給它獨立的地址空間,建立眾多的數據表來維護它的代碼段、堆棧段和數據段,這是一種"昂貴"的多任務工作方式。而運行于一個進程中的多個線程,它們彼此之間使用相同的地址空間,共享大部分數據,啟動一個線程所花費的空間遠遠小于啟動一個進程所花費的空間,而且,線程間彼此切換所需的時間也遠遠小于進程間切換所需要的時間。據統計,總的說來,一個進程的開銷大約是一個線程開銷的30倍左右,當然,在具體的系統上,這個數據可能會有較大的區別。

??????使用多線程的理由之二是線程間方便的通信機制。對不同進程來說,它們具有獨立的數據空間,要進行數據的傳遞只能通過通信的方式進行,這種方式不僅費時,而且很不方便。線程則不然,由于同一進程下的線程之間共享數據空間,所以一個線程的數據可以直接為其它線程所用,這不僅快捷,而且方便。當然,數據的共享也帶來其他一些問題,有的變量不能同時被兩個線程所修改,有的子程序中聲明為static的數據更有可能給多線程程序帶來災難性的打擊,這些正是編寫多線程程序時最需要注意的地方。
Linux上線程開發API概要
??????多線程開發在 Linux 平臺上已經有成熟的 pthread 庫支持。其涉及的多線程開發的最基本概念主要包含三點:線程,互斥鎖,條件。其中,線程操作又分線程的創建,退出,等待 3 種。互斥鎖則包括 4 種操作,分別是創建,銷毀,加鎖和解鎖。條件操作有 5 種操作:創建,銷毀,觸發,廣播和等待。其他的一些線程擴展概念,如信號燈等,都可以通過上面的三個基本元素的基本操作封裝出來。詳細請見下表:
在這里插入圖片描述1、線程創建

#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
// 返回:若成功返回0,否則返回錯誤編號
//pthread_t是無符號的長整型,第一個參數是pthread_t類型的指針,
//第個二參數是線程的屬性
//第三個參數是函數指針
//最后一個參數是給線程傳參的一個參數

當pthread_create成功返回時,由tidp指向的內存單元被設置為新創建線程的線程ID。attr參數用于定制各種不同的線程屬性,暫可以把它設置為NULL,以創建默認屬性的線程。

新創建的線程從start_rtn函數的地址開始運行,該函數只有一個無類型指針參數arg。如果需要向start_rtn函數傳遞的參數不止一個,那么需要把這些參數放到一個結構中,然后把這個結構的地址作為arg參數傳入。
線程的退出

單個線程可以通過以下三種方式退出,在不終止整個進程的情況下停止它的控制流:

1)線程只是從啟動例程中返回,返回值是線程的退出碼。

2)線程可以被同一進程中的其他線程取消。

3)線程調用pthread_exit:
pthread_exit函數

#include <pthread.h>
int pthread_exit(void *rval_ptr);

rval_ptr是一個無類型指針,與傳給啟動例程的單個參數類似。進程中的其他線程可以通過調用pthread_join函數訪問到這個指針。
線程等待

#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
// 返回:若成功返回0,否則返回錯誤編號

調用這個函數的線程將一直阻塞,直到指定的線程調用pthread_exit、從啟動例程中返回或者被取消。如果例程只是從它的啟動例程返回i,rval_ptr將包含返回碼。如果線程被取消,由rval_ptr指定的內存單元就置為PTHREAD_CANCELED。

可以通過調用pthread_join自動把線程置于分離狀態,這樣資源就可以恢復。如果線程已經處于分離狀態,pthread_join調用就會失敗,返回EINVAL。

如果對線程的返回值不感興趣,可以把rval_ptr置為NULL。在這種情況下,調用pthread_join函數將等待指定的線程終止,但并不獲得線程的終止狀態。
線程的脫離
一個線程或者是可匯合(joinable,默認值),或者是脫離的(detached)。當一個可匯合的線程終止時,它的線程ID和退出狀態將留存到另一個線程對它調用pthread_join。脫離的線程卻像守護進程,當它們終止時,所有相關的資源都被釋放,我們不能等待它們終止。如果一個線程需要知道另一線程什么時候終止,那就最好保持第二個線程的可匯合狀態。

pthread_detach函數把指定的線程轉變為脫離狀態。

#include <pthread.h>
int pthread_detach(pthread_t thread);
// 返回:若成功返回0,否則返回錯誤編號

本函數通常由想讓自己脫離的線程使用,就如以下語句:

pthread_detach(pthread_self());

線程ID獲取及比較

#include <pthread.h>
pthread_t pthread_self(void);
// 返回:調用線程的ID

對于線程ID比較,為了可移植操作,我們不能簡單地把線程ID當作整數來處理,因為不同系統對線程ID的定義可能不一樣。我們應該要用下邊的函數:

#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2);
// 返回:若相等則返回非0值,否則返回0

對于多線程程序來說,我們往往需要對這些多線程進行同步。同步(synchronization)是指在一定的時間內只允許某一個線程訪問某個資源。而在此時間內,不允許其它的線程訪問該資源。我們可以通過互斥鎖(mutex),條件變量(condition variable)和讀寫鎖(reader-writer lock)來同步資源。在這里,我們暫不介紹讀寫鎖。
代碼示例

#include<stdio.h>
#include<pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);void*func1(void *arg)
{static int ret=10;//如果不是 static 函數調用結束后 ret 的值會消失static char*p="t1 is run out";printf("t1 :%ld thread is created\n",(unsigned long)pthread_self());printf("t1:param is %d\n",*((int*)arg));pthread_exit((void*)p);
}
int main()
{int ret;int param=100;char *pret;pthread_t t1;ret=pthread_create(&t1,NULL,func1,(void*)&param);if(ret==0){printf("main:create t1 success\n");}printf("main : %ld \n",(unsigned long)pthread_self());pthread_join(t1,(void**)&pret);//這個函數用來等t1線程的退出,他是用在主線程中printf("main:t1 quite return is %s\n",pret);return 0;
}

體現線程共享內存空間代碼

{
#include<stdio.h>
#include<pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;//主進程和進程1和進程2都共享這一個全局變量
void*func1(void *arg)
{printf("t1 :%ld thread is created\n",(unsigned long)pthread_self());printf("t1:param is %d\n",*((int*)arg));while(1){printf("t1 printf is %d\n",g_data++);sleep(1);}
}void*func2(void *arg)
{printf("t2 :%ld thread is created\n",(unsigned long)pthread_self());printf("t2:param is %d\n",*((int*)arg));while(1){printf("t2 printf is %d\n",g_data++);sleep(1);}
}int main()
{int ret;int param=100;pthread_t t1;pthread_t t2;ret=pthread_create(&t1,NULL,func1,(void*)&param);if(ret==0){printf("main:create t1 success\n");}ret=pthread_create(&t2,NULL,func2,(void*)&param);if(ret==0){printf("main:create t2 success\n");}printf("main : %ld \n",(unsigned long)pthread_self());while(1){printf("main printf is %d\n",g_data++);sleep(1);}pthread_join(t1,NULL);//yong laidengdai t1 xiancheng tuichupthread_join(t2,NULL);//yong laidengdai t1 xiancheng tuichureturn 0;
}
//c此程序三個進程的運行順序沒有確定誰先誰后

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/272484.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/272484.shtml
英文地址,請注明出處:http://en.pswp.cn/news/272484.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Redis學習筆記1-Redis數據類型

Redis數據類型 Redis支持5種數據類型&#xff0c;它們描述如下&#xff1a; Strings - 字符串 字符串是 Redis 最基本的數據類型。Redis 字符串是二進制安全的&#xff0c;也就是說&#xff0c;一個 Redis 字符串可以包含任意類型的數據&#xff0c;一個字符串最大為 512M 字節…

30個非常有趣的404錯誤頁面設計欣賞

當用戶訪問一個不存在的頁面的時候就會出現404錯誤頁面&#xff0c;這對用戶來說是很不友好的。所以很多網站都會去設計一個新穎的錯誤頁面&#xff0c;以吸引用戶繼續瀏覽其它的網頁內容。今天這篇文章就收集了30個非常有趣的404錯誤頁面設計欣賞&#xff0c;希望能帶給你靈感…

線程同步之互斥量加鎖解鎖 死鎖

與互斥鎖相關API 互斥量&#xff08;mutex&#xff09;從本質上來說是一把鎖&#xff0c;在訪問共享資源前對互斥量進行加鎖&#xff0c;在訪問完成后釋放互斥量上的鎖。對互斥量進行加鎖后&#xff0c;任何其他試圖再次對互斥量加鎖的線程將會被阻塞直到當前線程釋放該互…

游戲開發-從零開始 002

個人開發者的游戲大部分需要完成的內容&#xff1a; 1.完整的游戲玩法邏輯&#xff08;核心&#xff09; 2.UI 3.游戲關卡設計 4.游戲旁白 5.交互細節 6.游戲分享接口 7.游戲道具 8.游戲排行榜&#xff0c;游戲社區&#xff0c;如 GameCenter 9.游戲內購 如 remove Ads 10.廣告…

5 個最佳的 Linux 桌面環境

打算把每個桌面都試用一遍&#xff0c;但是那很費時間&#xff0c;而且確實有很多桌面環境可供選擇&#xff0c;這就是我發表“最優秀的 Linux 桌面以及他們的優缺點”的目的&#xff0c;本文告訴你在選擇桌面時需要注意些什么&#xff0c;讓我們開始吧。1. KDE我想從第五個說起…

線程條件控制實現線程的同步

與條件變量相關API 條件變量是線程另一可用的同步機制。條件變量給多個線程提供了一個會合的場所。條件變量與互斥量一起使用時&#xff0c;允許線程以無競爭的方式等待特定的條件發生。 條件本身是由互斥量保護的。線程在改變條件狀態前必須首先鎖住互斥量&#xff0c…

自定義能夠for each的類,C#,Java,C++,C++/cli的實現方法

自定義類能夠被for each&#xff0c;應該算是個老生常談的話題了&#xff0c;相關的資料都很多&#xff0c;不過這里整理總結主流語言的不同實現方式&#xff0c;并比較部分細節上的差異。 第一種語言&#xff0c;也是實現起來最簡單的Java語言。在Java里&#xff0c;要被for e…

SQL Server 2008 R2:快速清除日志文件的方法

本例&#xff0c;快速清理“students”數據庫的日志&#xff0c;清理后日志文件不足1M。USE [master] GO ALTER DATABASE students SET RECOVERY SIMPLE WITH NO_WAIT GO ALTER DATABASE students SET RECOVERY SIMPLE GO USE students GO--此處需要注意&#xff…

linux網絡編程之字節序

進程間通信 特點&#xff1a;依賴于內核&#xff0c;造成缺陷——無法實現多機通信。 網絡編程 地址&#xff1a;由IP地址和端口號構成&#xff0c;端口號用來判斷客戶端接入哪個服務器。 數據的交流&#xff1a;涉及到協議&#xff08;http&#xff0c;tcp&#xff0c;udp&…

Oracle查看表空間和表空間中的對象

select * from user_tables;--查詢所有用戶表 select username,default_tablespace from user_users;--查詢當前表空間select tablespace_name from dba_tablespaces;--查詢所有表空間select tablespace_name, sum(bytes)/1024/1024 from dba_data_files group by tablespace_n…

C#中DateTime.Ticks屬性及Unix時間戳轉換

DateTime.Ticks&#xff1a;表示0001 年 1 月 1 日午夜 12:00:00 以來所經歷的 100 納秒數&#xff0c;即Ticks的屬性為100納秒&#xff08;1Ticks 0.0001毫秒&#xff09;。Unix時間戳&#xff1a;是從1970年1月1日&#xff08;UTC/GMT的午夜&#xff09;開始所經過的秒數&am…

WebBrowser控件的常用方法、屬性和事件

1. 屬性屬性說明Application如果該對象有效&#xff0c;則返回掌管WebBrowser控件的應用程序實現的自動化對象(IDispatch)。如果在宿主對象中自動化對象無效&#xff0c;這個程序將返回WebBrowser 控件的自動化對象Parent返回WebBrowser控件的父自動化對象&#xff0c;通常是一…

二維碼高亮

// 二維碼高亮。http://blog.sina.com.cn/s/blog_a843a8850102uy6w.html 轉載于:https://www.cnblogs.com/muyushifang07/p/5114667.html

socket 網絡 編程

網絡編程場景 自己是客戶端站在5棟樓前&#xff0c;自己要找到5棟樓中的一座并進入某一間房間&#xff0c;這時第二座樓上有人在用漢語&#xff08;tcp/udp&#xff09;說話,我的ip地址&#xff08;樓號&#xff09;是…&#xff0c;我的端口號&#xff08;房間號&#xff09;是…

7個免費的Linux FTP客戶端工具

在Dropbox、YouSendIt、idrive以及許多這樣云存儲和共享工具的幫助下&#xff0c;我們在互聯網上發送和共享大型文件變得容易起來。所有這些網站都可以幫助你在互聯網上傳送文件&#xff0c;但如果你要分享龐大的數據&#xff0c;這依然是很復雜的事情。所以&#xff0c;你需要…

樹莓派的幾種登錄方式及樹莓派的網絡配置

&#xff08;1&#xff09;HDMI 視頻線 連接到顯示器 &#xff08;2&#xff09;串口 設備破解&#xff1a; 默認情況下,樹莓派的串口和藍牙連接&#xff0c;把串口用來數據通信。 修改系統配置&#xff0c;啟用串口登錄樹莓派 1.打開SD卡根目錄的"config.txt"文件…

C語言之常量與變量

1.常量 1.1整型常量:短整型(short int),整型(int),長整型(long int).短整型和長整型都可省慮后面的int,三者唯一的區別就是內存大小的區別,從小到大依次為short < int < long. int a;short int b;long int c;  printf("%d,%d",a,b);  printf("%ld&quo…

【收集】11款Linux數據恢復工具

如果你使用的是Linux操作系統&#xff0c;那么你一定想知道一旦硬盤崩潰的話又該如何保存和恢復數據。其實&#xff0c;現在有很多Linux數據恢復工具可以讓我們擺脫數據安全的困擾。小編已經為各位準備好了一些最好的Linux數據恢復工具&#xff0c;歡迎大家品鑒。KnoppixKnoppi…

VIM更新

1、可以用以下指令 sudo apt-get install vim2、默認的是國外的源&#xff0c;apt-get 安裝失敗的時候&#xff0c;我們更換成國內的源。 &#xff08;1&#xff09; 編輯sources.list 打開終端輸入 sudo nano /etc/apt/sources.list用#注釋或直接刪除原有的內容&#xff0c…

svn 常用操作命令

檢出svn co svn://xxxxx/svn/ios --username jm --password 123 通常情況下&#xff0c;命令svn add *會忽略所有已經在版本控制之下的目錄&#xff0c;有時候&#xff0c;你會希望添加所有工作拷貝的未版本化文件&#xff0c;包括那些隱藏在深處的文件&#xff0c;可以使用svn…