linux 信號_Linux的信號和線程

286919f96f05b9930e9d67c30fac507d.png
Linux的信號和線程-Tech Talk 讓技術發出聲音?www.ttalk.im

什么是線程

線程,有時被稱為輕量級進程(Lightweight Process,LWP),是程序執行流的最小單元。一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成,每一個程序都至少有一個線程,若程序只有一個線程,那就是程序本身。

同時線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程自己不擁有系統資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的全部資源。

一個線程可以創建和撤消另一個線程,同一進程中的多個線程之間可以并發執行。由于線程之間的相互制約,致使線程在運行中呈現出間斷性。因此線程也有就緒、阻塞和運行三種基本狀態。就緒狀態是指線程具備運行的所有條件,邏輯上可以運行,在等待處理機;運行狀態是指線程占有處理機正在運行;阻塞狀態是指線程在等待一個事件(如某個信號量),邏輯上不可執行。

什么是信號

信號是一種IPC通信的形式,一般在Unix,類Unix或POSIX兼容的系統中使用。信號是一種異步通知進程或同進程中某個指定線程的方式。 當信號被發送到進程的時候,操作系統會中斷進程的控制流程,并且在執行非原子性的CPU指令時可以中斷進程。

信號使用的風險(新手坑)

信號處理在存在競態的,因為信號本身是異步的,在處理一個信號的過程中,令一個信號(甚至肯能是同類型的信號)會被直接發送到進程中請求進程處理。 信號是可以打斷系統調用的,不謹慎處理會引起程序自身的混亂,所以進程的信號處理過程,盡量做到沒有副作用,也不要使用不可重入的函數。

Linux的線程

LinuxThreads

在Linux的上古時代,Linux的線程技術和POSIX的標準是不同的,它使用自己的LinuxThreads庫。這會為我們帶來什么影響呢?

讓我們來回顧一下 LinuxThreads 設計細節的一些基本理念:

  1. 系統必須能夠響應終止信號并殺死整個進程。
  2. 以堆棧形式使用的內存回收必須在線程完成之后進行。因此,線程無法自行完成這個過程。
  3. 終止線程必須進行等待,這樣它們才不會進入僵尸狀態。
  4. 線程本地數據的回收需要對所有線程進行遍歷;這必須由管理線程來進行。
  5. 如果主線程需要調用 pthread_exit(),那么這個線程就無法結束。主線程要進入睡眠狀態,而管理線程的工作就是在所有線程都被殺死之后來喚醒這個主線程。

為了維護線程本地數據和內存,LinuxThreads使用了進程地址空間的高位內存(就在堆棧地址之下)。 同步元語是使用信號來實現的。例如,線程會一直阻塞,直到被信號喚醒為止。并且,LinuxThreads將每個線程都是作為一個具有惟一進程ID的進程實現的。LinuxThreads接收到終止信號之后,管理線程就會使用相同的信號殺死所有其他線程(進程)。 由于異步信號是內核以進程為單位分發的,而LinuxThreads的每個線程對內核來說都是一個進程,且沒有實現“線程組”,因此,某些語義不符合POSIX標準,比如沒有實現向進程中所有線程發送信號。如果核心不提供實時信號,LinuxThreads將使用SIGUSR1和SIGUSR2作為內部使用的restart和cancel信號,這樣應用程序就不能使用這兩個原本為用戶保留的信號了。在Linux kernel 2.1.60以后的版本都支持擴展的實時信號(從_SIGRTMIN到_SIGRTMAX),因此不存在這個問題。根據 LinuxThreads 的設計,如果一個異步信號被發送了,那么管理線程就會將這個信號發送給一個線程,如果這個線程現在阻塞了這個信號,那么這個信號也就會被掛起,因此某些信號的缺省動作難以在現行體系上實現,比如SIGSTOP和SIGCONT,LinuxThreads只能將一個線程掛起,而無法掛起整個進程。

LinuxThreads帶來了什么問題

首先我們說下POSIX是如何定義多線程的:POSIX下一個多線程的進程只有一個PID。 根據上面我們對LinuxThreads的描述,我們可以總結出LinuxThreads有下面這些問題:

  1. 它使用管理線程來創建線程,并對每個進程所擁有的所有線程進行協調。這增加了創建和銷毀線程所需要的開銷。
  2. 由于它是圍繞一個管理線程來設計的,因此會導致很多的上下文切換的開銷,這可能會妨礙系統的可伸縮性和性能。
  3. 由于管理線程只能在一個 CPU 上運行,因此所執行的同步操作在 SMP 或 NUMA 系統上可能會產生可伸縮性的問題。
  4. 由于線程的管理方式,以及每個線程都使用了一個不同的進程 ID,因此 LinuxThreads 與其他與 POSIX 相關的線程庫并不兼容。
  5. 信號用來實現同步原語,這會影響操作的響應時間。另外,將信號發送到主進程的概念也并不存在。因此,這并不遵守 POSIX 中處理信號的方法。

我們在這里不關注性能如何只關注POSIX兼容和信號處理問題。

NPTL

LinuxThreads的問題,特別是兼容性上的問題,嚴重阻礙了Linux上的跨平臺應用(如Apache)采用多線程設計,從而使得Linux上的線程應用一直保持在比較低的水平。在Linux社區中,已經有很多人在為改進線程性能而努力,其中既包括用戶級線程庫,也包括核心級和用戶級配合改進的線程庫。目前最為人看好的有兩個項目,一個是RedHat公司牽頭研發的NPTL(Native Posix Thread Library),另一個則是IBM投資開發的NGPT(Next Generation Posix Threading),二者都是圍繞完全兼容POSIX 1003.1c,同時在核內和核外做工作以而實現多對多線程模型。這兩種模型都在一定程度上彌補了LinuxThreads的缺點,且都是重起爐灶全新設計的。 NPTL的設計目標歸納可歸納為以下幾點:

  1. POSIX兼容性
  2. SMP結構的利用
  3. 低啟動開銷
  4. 低鏈接開銷(即不使用線程的程序不應當受線程庫的影響)
  5. 與LinuxThreads應用的二進制兼容性
  6. 軟硬件的可擴展能力
  7. 多體系結構支持
  8. NUMA支持

在技術實現上,NPTL仍然采用1:1的線程模型,并配合glibc和最新的Linux Kernel2.5.x開發版在信號處理、線程同步、存儲管理等多方面進行了優化。和LinuxThreads不同,NPTL沒有使用管理線程,核心線程的管理直接放在核內進行,這也帶了性能的優化。

Linux線程總結

比較新的Linux都已經開始使用NPTL了,所以我們可以忽略LinuxThreads的存在了,介紹它主要是為了讓諸位讀者更深入的了解線程和信號的恩恩怨怨(不要丟雞蛋)。

Linux的信號

Linux是如何處理信號的

隨著Linux的內核版本不斷提升,Linux的信號現在已經可以按照線程級別的觸發了,換句話說就是,每個線程可以關注自己的信號了,并且可以區別性對待了。那我們需要注意什么呢?

在多線程應用中,我們應當使用sigaction來代替singal函數,因為按POSIX的說法singal函數并沒有明確定義自己在多線程應用中的行為。

可以使用pthread_sigmask來為每個線程設置獨立的信號掩碼。同時在多線程應用中應當避免使用sigprocmask這個函數,原因也是POSIX中該函數并沒有明確定義自己在多線程應用中的行為。

這個時候,有人會產生疑問了,那么多線程下kill發出的進程級別的信號A怎么辦?Linux是這樣解決的,它會把這個信號交付給任意一個沒有屏蔽信號A的線程。如果這信號沒有被任何線程設置handler進行處理,就會觸發POSIX規定的默認動作。

接著有人就會問,我怎么向某個線程發消息呢,POSIX為我們準備了pthread_kill函數,我們可以直接向特定的線程發送消息。那么如果一個線程收到信號A,但是自己沒有安裝handler會發生什么?其實和進程級別的信號處理方法一樣,直接觸發默認動作,同樣會結束整個進程。

如何避免新手坑

在具有事件循環的應用中,在信號的的handler中,可以將信號直接放入程序的隊列中,立刻返回。這樣直到線程從程序的隊列中取出這個信號為止,整個線程看起來就像沒有“中斷”。 如果不知道該怎么做,去看看著名的libev吧。

信號SIGSEGV

這個信號,也許是大家最不想見到,為什么呢?我們看這個信號的定義:

當當前程序對內存的引用無效時,就會產生當前信號,也就是我們常說的“段違例”。

以下幾種情況會產生該信號:

1.進程引用的內存頁面不存在(例如,該頁面位于堆和棧之間的映射的區域)
2.進程試圖更新只讀內存頁(例如,程序文本段或已經被標記為只讀的內存映射區域)
3.進程試圖在用戶態去訪問內核部分的內存

好了,我們都知道這個信號引發的結果就是進程退出。不過我們都忽視了一個問題,在現代的Linux上,按照POSIX的定義,這個信號是系統產生的線程級別的信號。換句話說,如果某個線程A出現了內存引用無效,那么產生的信號,會投遞到線程A的信號隊列中,而不是像進程級別的信號無法確定接受者是誰。

JVM的安全區域

如果我們想讓所有Java線程停下來的時候,在JVM的JavaThread執行到大家所知道的test 特定頁面的指令時,就會因為更新不可讀頁面而觸發SIGSEGV信號。那么對于那些正在執行native代碼的JavaThread該怎么辦,JVM中的注釋寫的非常清楚,native返回JVM時會檢查是否能返回的。

好了再多說一句,JVM是如果將特定內存保護起來的呢?這個需要看操作系統的API了,在Linux中是mprotect。

總結

多讀讀POSIX標準和Intel的CPU體系結構,會讓自己在開發變的容易些。

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

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

相關文章

tomcat部署教程

參考博客地址: https://blog.csdn.net/xiaoyu940601/article/details/54950673轉載于:https://www.cnblogs.com/liuniublogs/p/10019068.html

選擇文字就能選擇復選框

更方便的單選框下面為腳本顯示區  看看下面的選擇框,似乎沒有什么不同的。微妙之處在于,選擇項目時不必非得在框內點擊鼠標了,在文本上選擇即可。不信試一試吧。 經常來這里 偶爾來看看 轉載于:https://www.cnblogs.com/leevane/archive/200…

python 數據結構

一. 深入鏈表 先來介紹一些鏈表具備的一些常用方法: append(x) : 把一個元素添加到鏈表的結尾 extend(L) : 將另外一個鏈表合并到該鏈表中 insert(i,x) : 插入一個元素到指定位置的前面 remove(x) : 刪除鏈表中第一個值為x的元素 如果沒有這樣的元素 則返回錯誤 pop…

python筆試編程題_Python——面試編程題

一、python----輸出1-100之和的方法 方法一: print(sum(range(1,101))) 方法二: from functools import reduce print(reduce(lambda x, y: xy, range(101))) 方法三: t0 for i in range(101): ti print(t) 方法四: print(sum([x for x in ra…

go語言項目優化(經驗之談)

1 Go的應用場景 在斗魚我們將GO的應用場景分為以下三類,緩存類型數據,實時類型數據,CPU密集型任務。這三類應用場景都有著各自的特點。 ● 緩存類型數據在斗魚的案例就是我們的首頁,列表頁,這些頁面和接口的特點是不同…

AddTransient、AddSingleton、AddScoped 三者都應該在什么場景下使用

網上隨便一搜,能搜出一大堆對三者進行區別分析的文章,但是呢,理論是一回事,實際使用又是另外一回事,到底在何種場景下應該使用何種注入方式呢? 通過這篇文章和我自身的實際經驗,來說一說實際應用…

python交互界面用圖片當背景_wxPython實現窗口用圖片做背景

本文實例為大家分享了wxPython實現窗口用圖片做背景的具體代碼,供大家參考,具體內容如下 效果圖:實現代碼: #!/usr/bin/env python # -*- encoding:utf-8 -*- import wx class MyPanel(wx.Panel): def __init__(self,parent,id): …

css超出隱藏顯示省略號

width: 300px; overflow: hidden;/*超出部分隱藏*/ text-overflow:ellipsis;/* 超出部分顯示省略號 */ white-space: nowrap;/*規定段落中的文本不進行換行 */ 轉載于:https://www.cnblogs.com/songmengwen1124/p/11354620.html

信號為E時,如何讓語音識別脫“網”而出?

歡迎大家前往騰訊云社區,獲取更多騰訊海量技術實踐干貨哦~ 本文由騰訊教育云發表于云社區專欄 一般沒有網絡時,語音識別是這樣的 ▽ 而同等環境下,嵌入式語音識別,是這樣的 ▽ 不僅可以幫您邊說邊識、出口成章,有個性化…

TwinSocketStream

使用TwinSocketStream 當為一個blocking連接實現一個線程時,你必須確定在連接的另一端的socket是準備寫還是讀.Blocking連接不會通知socket當它準備好寫或讀操作的時候.想看看連接是否準備好,使用TWinSocketStream對象.TWinSocketStream提供一個方法去幫助調整讀或寫操作時間的…

c 字符串轉數字_C語言實現十進制轉216進制、十六進制轉十進制

1、十進制轉2~16進制【問題描述】從鍵盤輸入十進制整數num及轉換的進制數base,將整數num轉換為base進制(base取值范圍為 2~16)。方法為:十進制數除base取余法,即十進制數除以base,余數為權位上的數&#xf…

Mysql循環語句,死循環解決辦法

delimiter // #定義標識符為雙斜杠 drop procedure if exists test; #如果存在test存儲過程則刪除 create procedure test() #創建無參存儲過程,名稱為testbegindeclare i int; #申明變量set i 0; …

QML-關于Qt.rgba()顏色無法正常顯示問題

GitHub:八至 作者:狐貍家的魚 本文鏈接:關于Qt.rgba()顏色的正確寫法 當在正常給color屬性寫顏色的時候,用十六進制能正常顯示,但是用Qt.rgba()時,顏色無法正常顯示出來。 按照文檔的正常寫法: color: Qt.r…

一個簡單的LINQ TO XML, AJAX 例子[譯]

這個教程是用Visual Studio.net 2008建立,也可以使用VS2005,但你需要從這里下載安裝Microsofts ASP.NET AJAX Extensions,AJAX和LINQ是微軟目前主要焦點,兩個看上去不足為奇,但背后都隱藏著巨大的潛力和力量。在這個示…

1.ASP.NET Core介紹

優點: 1.跨平臺,高性能,開源,運行在.Net Core 或.Net Framework框架上(asp.net core 3.0及以后只支持.Net Core)。 2.各平臺上開發工具支持,能夠開發web應用,webapi,移動…

python3性能還低嗎_Python3 vs. Python2 大作戰,誰將是性能之王?

渲染 HTML 模板 django_html 測試將使用 Django 模板渲染引擎來構建一個 150x150 的 HTML 表格。 它利用了 Django 引擎的 Content 和 Template 類。如圖所示,Python 3.7 比 Python 2.7 快 1.19 倍,但除此之外,其他 Python 3 版本都沒有 Pyth…

python day08

一 文件處理補充 控制文件中光標移動 1 f.read(n): l.文件打開方式為文本模式的時,代表讀取N個字符 ll.文件打開方式為b模式時,讀取N個字節 強調:只有在read(n)模式下 N代表字符個數,除此之外的是以字節為單位 2 f.seek(): 光標移動是以字節為單位的整數移動. 三種模式:(分別為…

百度地圖移動端開發和ArcGIS for Android 開發入門

打開鏈接http://pan.baidu.com/s/1eQpFNWY,可以查看 轉載于:https://www.cnblogs.com/David-Young/p/3827058.html

VSCode 小雞湯 第00期 —— 安裝和入門

簡介 這將是一個新的系列,將會以 Visual Studio Code(后文都簡稱為 VSCode 啦)的操作,環境配置,插件介紹為主,為大家不定期的介紹 VSCode 的一些操作技巧,所以取名 VSCode 小雞湯,本…

.net生成文字圖片

System.Drawing.Bitmap bmpnew Bitmap(Bitmap.FromFile(Server.MapPath("42.jpg")));//載入圖片 System.Drawing.Graphics gGraphics.FromImage(bmp); g.DrawString("abcd測試",new Font("黑體",18),new SolidBrush(Co…