Linux系統編程---13(線程控制函數,創建線程,循環創建多個線程,線程間共享全局變量)

線程控制

操作系統并沒有提供創建線程的系統調用接口,因此大佬們封裝了一個線程的接口庫實現線程控制。意為著用戶創建線程都使用的是庫函數(所以有時候我們說創建的線程是一個用戶態線程,但是在內核中對應有一個輕量級進程實現線程程序的調度)

進程ID == 線程組id–tgid == 主線程pid

線程控制函數

pthread_self 函數

獲取線程 ID。其作用對應進程中 getpid() 函數。
pthread_t pthread_self(void); 返回值:成功:0; 失敗:無!
線程 ID:pthread_t 類型,本質:在 Linux 下為無符號整數(%lu),其他系統中可能是結構體實現
線程 ID 是進程內部,識別標志。(兩個進程間,線程 ID 允許相同)
注意:不應使用全局變量 pthread_t tid,在子線程中通過 pthread_create 傳出參數來獲取線程 ID,而應使用 pthread_self

pthread_create 函數

創建一個新線程。 其作用,對應進程中 fork() 函數。
int pthread_create (pthread_t * thread,const pthread_attr_t *attr,void* (*start_routine)(void*),void* arg);
返回值:成功:0; 失敗:錯誤號 -----Linux 環境下,所有線程特點,失敗均直接返回錯誤號。
參數
pthread_t:當前 Linux 中可理解為:typedef unsigned long int pthread_t;
參數 1:傳出參數,保存系統為我們分配好的線程 ID
參數 2:通常傳 NULL,表示使用線程默認屬性。若想使用具體屬性也可以修改該參數。
參數 3:函數指針,指向線程主函數(線程體),該函數運行結束,則線程結束。
參數 4:線程主函數執行期間所使用的參數。

在一個線程中調用 pthread_create()創建新的線程后,當前線程從 pthread_create()返回繼續往下執行,而新的線 程所執行的代碼由我們傳給 pthread_create 的函數指針 start_routine 決定。
start_routine 函數接收一個參數,是通過 pthread_create 的 arg 參數傳遞給它的,該參數的類型為 void *,這個指針按什么類型解釋由調用者自己定義。
start_routine 的返回值類型也是 void*,這個指針的含義同樣由調用者自己定義。start_routine 返回時,這個線程就 退出了,其它線程可以調用 pthread_join 得到 start_routine 的返回值,類似于父進程調用 wait(2)得到子進程的退出 狀態,稍后詳細介紹 pthread_join。
pthread_create 成功返回后,新創建的線程的 id 被填寫到 thread 參數所指向的內存單元。我們知道進程 id 的類 型是 pid_t,每個進程的 id 在整個系統中是唯一的,調用 getpid(2)可以獲得當前進程的 id,是一個正整數值。
線程 id 的類型是 thread_t,它只在當前進程中保證是唯一的,在不同的系統中 thread_t 這個類型有不同的實現,它可能 是一個整數值,也可能是一個結構體,也可能是一個地址,所以不能簡單地當成整數用printf打印,調用pthread_self(3) 可以獲得當前線程的 id。
pthread_t到底是什么類型呢?取決于實現。對于Linux目前實現的NPTL實現而言,pthread_t類型的線程ID,本質就 是一個進程地址空間上的一個地址。線程空間的首地址

練習:創建一個新線程,打印線程 ID。注意:鏈接線程庫 -lpthread
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>void *thrd_func(void *arg)
{//子線程的IDprintf(" In thread id = %lu,pid = %u\n",pthread_self(),getpid());return NULL;
}int main(void)
{pthread_t tid;int ret;//主控線程IDprintf(" In main1 id = %lu,pid = %u\n",pthread_self(),getpid());ret = pthread_create(&tid,NULL,thrd_func,NULL);if(ret != 0){ printf("pthread_create error\n");exit(1);}   printf(" In main2 id = %lu,pid = %u\n",pthread_self(),getpid());         sleep(1);//主控線程等待子線程1秒,讓它打印return 0;
}

在這里插入圖片描述
思考
由于 pthread_create 的錯誤碼不保存在 errno 中,因此不能直接用 perror(3)打印錯誤信息,可以先用 strerror(3) 把錯誤碼轉換成錯誤信息再打印。如果任意一個線程調用了 exit 或_exit,則整個進程的所有線程都終止,由于從 main 函數 return 也相當于調用 exit,為了防止新創建的線程還沒有得到執行就終止,我們在 main 函數 return 之前 延時 1 秒,這只是一種權宜之計,即使主線程等待 1 秒,內核也不一定會調度新創建的線程執行。

循環創建多個線程,每個線程打印自己是第幾個被創建的線程。(類似于進程循環創建子進程)
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>void *thrd_func(void *arg)
{int i=(int)arg;sleep(i);    //子線程的IDprintf("%d th In thread id = %lu,pid = %u\n", i+1 ,pthread_self(),getpid());return NULL;
}int main(void)
{pthread_t tid;int ret,i;for(i=0;i < 5; i++){   ret = pthread_create(&tid,NULL,thrd_func,(void *)i);if(ret != 0){ fprintf(stderr,"pthread_create error:%s\n",strerror(ret));exit(1);}   }   sleep(i);// 主控線程等待子線程1秒,讓它打印                              return 0;// 將當前進程退出
}

在這里插入圖片描述
注意:將 pthread_create 函數參 4 修改為(void*)&i, 將線程主函數內改為 i=*((int*)arg) 不可以

線程間共享全局變量

驗證

#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>int var =100;void *tfn(void * arg)
{//子線程修改varvar = 200;printf("thread\n");return NULL;
}int main(void)
{printf("At first var = %d\n",var);pthread_t tid;pthread_create(&tid,NULL,tfn,NULL);sleep(1);//等子線程退出后,再次打印var                                            printf("after pthread_create, var = %d\n",var);return 0;
}

在這里插入圖片描述
線程默認共享數據段、代碼段等地址空間,常用的是全局變量。而進程不共享全局變量,只能借助 mmap

pthread_exit 函數

將單個線程退出
void pthread_exit (void*retval); 參數:retval 表示線程退出狀態,通常傳 NULL

思考:使用 exit 將指定線程退出,可以嗎?

結論:線程中,禁止使用 exit 函數,會導致進程內所有線程全部退出。
在不添加 sleep 控制輸出順序的情況下。pthread_create 在循環中,幾乎瞬間創建 5 個線程,但只有第 1 個線程 有機會輸出(或者第 2 個也有,也可能沒有,取決于內核調度)如果第 3 個線程執行了 exit,將整個進程退出了, 所以全部線程退出了。
所以,多線程環境中,應盡量少用,或者不使用 exit 函數,取而代之使用 pthread_exit 函數,將單個線程退出。 任何線程里 exit 導致進程退出,其他線程未工作結束,主控線程退出時不能 return 或 exit。
另注意,pthread_exit 或者 return 返回的指針所指向的內存單元必須是全局的或者是用 malloc 分配的,不能在 線程函數的棧上分配,因為當其它線程得到這個返回指針時線程函數已經退出了。

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

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

相關文章

Linux系統編程---14(回收子線程,回收多個子線程,線程分離,殺死線程)

回收子線程 pthread_join 函數 阻塞等待線程退出&#xff0c;獲取線程退出狀態 其作用&#xff0c;對應進程中 waitpid() 函數。 int pthread_join (pthread_t thread,void** retval); 成功&#xff1a;0&#xff0c;失敗&#xff1a;錯誤號 參數&#xff1a;thread&#x…

Linux系統編程----15(線程與進程函數之間的對比,線程屬性及其函數,線程屬性控制流程,線程使用注意事項,線程庫)

對比 進程 線程 fork pthread_create exit (10) pthread_exit &#xff08;void *&#xff09; wait (int *) pthread_join &#xff08;&#xff0c;void **&#xff09;阻塞 kill pthread_cancel ();必須到取消點&#xff08;檢查點&#xff09;&#xff1a;…

內核雙向循環鏈表

#include <string.h>#include <stdio.h>#include <stdlib.h>#include<malloc.h>#include <arpa/inet.h>//鏈表頭結構struct list_head{struct list_head *next,*prev;};//真正實現鏈表插入操作void _list_add(struct list_head *nnew,struct lis…

Linux系統編程----16(線程同步,互斥量 mutex,互斥鎖的相關函數,死鎖,讀寫鎖)

同步概念 所謂同步&#xff0c;即同時起步&#xff0c;協調一致。不同的對象&#xff0c;對“同步”的理解方式略有不同。如&#xff0c;設備同步&#xff0c;是指在兩 個設備之間規定一個共同的時間參考&#xff1b;數據庫同步&#xff0c;是指讓兩個或多個數據庫內容保持一致…

轉移字符的轉換

使得網頁上不會顯示 \x0a\x0a \x0a \x0a \x0a \x0a 類似的字符static int te_escape_isDec(char *ptr, unsigned int len) { …

Linux系統編程---17(條件變量及其函數,生產者消費者條件變量模型,生產者與消費者模型(線程安全隊列),條件變量優點,信號量及其主要函數,信號量與條件變量的區別,)

條件變量 條件變量本身不是鎖&#xff01;但它也可以造成線程阻塞。通常與互斥鎖配合使用。給多線程提供一個會合的場所。 主要應用函數&#xff1a; pthread_cond_init 函數pthread_cond_destroy 函數pthread_cond_wait 函數pthread_cond_timedwait 函數pthread_cond_signa…

好友

http://blog.csdn.net/liangyuannao/article/details/8583139

Linux系統編程---18(線程池相關概念及其實現)

線程池 概念&#xff1a; 一堆線程任務隊列 作用 避免大量線程頻繁的創建/銷毀時間成本避免瞬間大量線程創建耗盡資源&#xff0c;程序崩潰危險 實現 創建固定數量的線程創建一個線程安全的任務隊列 一種線程使用模式。 線程過多會帶來調度開銷&#xff0c;進而影響緩…

設計模式--1(設計模式基礎,設計模式基本原則,設計模式分類)

設計模式基礎 模式 在一定環境中解決某一問題的方案&#xff0c;包括三個基本元素–問題&#xff0c;解決方案和環境。大白話&#xff1a;在一定環境下&#xff0c;用固定套路解決問題。 設計模式 是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使…

source insight 使用技巧

source insight 使用技巧 1 sourceinsight screen font 的默認字體是Verdana的&#xff0c;它是一直變寬字體。在Document style中可以將字體改為定寬的Courier2 document options->auto indent 去掉indent Open Brace和Indent Close Brace的效果: 繼上一段&#xff0c;在…

設計模式----2(簡單工廠模式的概念,簡單工廠模式的實現,簡單工廠模式的優缺點)

簡單工廠模式 簡單工廠模式的概念 簡單工廠模式屬于類的創建型模式,又叫做靜態工廠方法模式。通過專門定義一個類來負 責創建其他類的實例&#xff0c;被創建的實例通常都具有共同的父類。 具體分類 工廠&#xff08;Creator&#xff09;角色 簡單工廠模式的核心&#xff0…

Redis常見問題及其一些重點知識總結

1、什么是 Redis&#xff1f;簡述它的優缺點&#xff1f; Redis 的全稱是&#xff1a;Remote Dictionary.Server&#xff0c;本質上是一個 Key-Value 類型的內存數據庫&#xff0c;很像 memcached&#xff0c;整個數據庫統統加載在內存當中進行操作&#xff0c;定期通過異步操…

shell生成隨機文件名

1 #!/bin/bash 2 # tempfile-name.sh: 臨時文件名產生器 3 4 BASE_STRmcookie # 32-字符的 magic cookie. 5 POS11 # 字符串中隨便的一個位置. 6 LEN5 # 取得 $LEN 長度連續的字符串. 7 8 prefixtemp # 最終的一個臨時文…

設計模式---3(工廠方法模式的概念,工廠方法模式的實現,工廠方法模式和簡單工廠模式比較)

工廠方法模式 概念 工廠方法模式同樣屬于類的創建型模式又被稱為多態工廠模式 。 工廠方法模式的意義 定義一個創建產品對象的工廠接口&#xff0c;將實際創建工作推遲到子類當中。 核心工廠類不再負責產品的創建&#xff0c;這樣核心類成為一個抽象工廠角色&#xff0c;僅…

設計模式---4(抽象工廠模式的概念,產品組和產品等級的概念,抽象工廠模式的實現)

抽象工廠模式 抽象工廠模式的概念 抽象工廠模式是所有形態的工廠模式中最為抽象和最其一般性的。抽象工廠模式可以向 客戶端提供一個接口&#xff0c;使得客戶端在不必指定產品的具體類型的情況下&#xff0c;能夠創建多個產品 族的產品對象。 抽象工廠的角色及其職責 抽象工…

Win32項目關于MessageBox參數的詳細說明

函數功能&#xff1a;該函數創建、顯示、和操作一個消息框。消息框含有應用程序定義的消息和標題&#xff0c;加上預定義圖標與Push&#xff08;下按&#xff09;按鈕的任何組合。 函數原型&#xff1a;int MessageBox(HWND hWnd,LPCTSTR IpCaption,UINT…

w3af解析

1. w3af簡介 w3afis a Web Application Attack and Audit Framework.即Web應用攻擊和審計框架。w3af用python編寫&#xff0c;依賴的庫主要有2類&#xff0c;分別如下&#xff1a; <1> Core requirements: Python 2.6 fpconst-0.7.2&#xff1a;用于處理IEEE 754浮點…

1.c++中初始化列表和構造函數初始化的區別是什么?2.類的成員變量的初始化順序是按照聲明順序嗎?

初始化列表和構造函數初始化的區別是什么&#xff1f; 初始化和賦值對內置類型的成員沒有太大的區別&#xff0c;在成員初始化列表和構造函數體內進行&#xff0c;在性能和結果上都是一樣的。只有一些需要注意的事項 初始化列表一般情況如下&#xff1a; Date(int year, int …

設計模式---5(建造者模式的概念及其實現,建造者模式的角色與職責,建造者模式和工廠模式的區別)

建造者模式 建造者模式的概念 Builder 模式也叫建造者模式或者生成器模式&#xff0c;是由 GoF 提出的 23 種設計模式中的一種。 Builder 模式是一種對象創建型模式之一&#xff0c;用來隱藏復合對象的創建過程&#xff0c;它把復合對象的 創建過程加以抽象&#xff0c;通過子…

system阻塞SIGCHLD信號原因

system阻塞SIGCHLD信號原因 標簽&#xff1a; c 2014-11-08 11:58 198人閱讀 評論(0) 收藏 舉報 分類&#xff1a; linux編程&#xff08;1&#xff09; 代碼1&#xff1a;APUE10.18節的system函數源代碼 int system(const char *cmdstring) /* with appropriate signal ha…