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

歡迎訪問 生活随笔!

生活随笔

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

linux

linux 信号_Linux的信号和线程

發布時間:2023/12/9 linux 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 信号_Linux的信号和线程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

什么是線程

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

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

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

什么是信號

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

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

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

Linux的線程

LinuxThreads

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

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

  • 系統必須能夠響應終止信號并殺死整個進程。
  • 以堆棧形式使用的內存回收必須在線程完成之后進行。因此,線程無法自行完成這個過程。
  • 終止線程必須進行等待,這樣它們才不會進入僵尸狀態。
  • 線程本地數據的回收需要對所有線程進行遍歷;這必須由管理線程來進行。
  • 如果主線程需要調用 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有下面這些問題:

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

  • POSIX兼容性
  • SMP結構的利用
  • 低啟動開銷
  • 低鏈接開銷(即不使用線程的程序不應當受線程庫的影響)
  • 與LinuxThreads應用的二進制兼容性
  • 軟硬件的可擴展能力
  • 多體系結構支持
  • 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體系結構,會讓自己在開發變的容易些。

    總結

    以上是生活随笔為你收集整理的linux 信号_Linux的信号和线程的全部內容,希望文章能夠幫你解決所遇到的問題。

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