多線程是什麼?鎖是什麼?資訊量是什麼?以及各自的用處,多線程資訊量

來源:互聯網
上載者:User

多線程是什麼?鎖是什麼?資訊量是什麼?以及各自的用處,多線程資訊量

線程的概念:

  • 每個正在系統上啟動並執行程式都是一個進程。每個進程包含一到多個線程。進程也可能是整個程式或者是部分程式的動態執行。線程是一組指令的集合,或者是程式的特殊段,它可以在程式裡獨立執行。也可以把它理解為代碼啟動並執行上下文。所以線程基本上是輕量級的進程,它負責在單個程式裡執行多任務。通常由作業系統負責多個線程的調度和執行。
  • 線程是程式中一個單一的順序控制流程程.在單個程式中同時運行多個線程完成不同的工作,稱為多線程.
  • 線程和進程的區別在於,子進程和父進程有不同的代碼和資料空間,而多個線程則共用資料空間,每個線程有自己的執行堆棧和程式計數器為其執行內容.多線程主要是為了節約CPU時間,發揮利用,根據具體情況而定. 線程的運行中需要使用電腦的記憶體資源和CPU。

多線程的概念

  • 多線程是指從軟體或者硬體上實現多個線程並發執行的技術.
  • 多線程是為了同步完成多項任務,不是為了提高運行效率,而是為了提高資源使用效率來提高系統的效率。線程是在同一時間需要完成多項任務的時候實現的。
  • 最簡單的比喻多線程就像火車的每一節車廂,而進程則是火車。車廂離開火車是無法跑動的,同理火車也不可能只有一節車廂。多線程的出現就是為了提高效率。

如果你的應用程式需要採取以下的操作,那麼你盡可在編程的時候考慮多線程機制:

  • 連續的操作,需要花費忍無可忍的過長時間才可能完成
  • 並行計算
  • 為了等待網路、檔案系統、使用者或其他I/O響應而耗費大量的執行時間
  • 所以說,在動手之前,先保證自己的應用程式中是否出現了以上3種情形。

為什麼需要多線程(解釋何時考慮使用線程)

  • 從使用者的角度考慮,就是為了得到更好的系統服務;從程式自身的角度考慮,就是使目標任務能夠儘可能快的完成,更有效利用系統資源。綜合考慮,一般以下場合需要使用多線程:
  • 程式包含複雜的計算任務時,主要是利用多線程擷取更多的CPU時間(資源)。
  • 處理速度較慢的外圍裝置.比如:列印時。再比如網路程式,涉及資料包的收發,時間因素不定。使用獨立的線程處理這些任務,可使程式無需專門等待結果。
  • 程式設計自身的需要.WINDOWS系統是基於訊息迴圈的搶佔式多任務系統,為使訊息迴圈系統不至於阻塞,程式需要多個線程的來共同完成某些任務。
  • 每個正在系統上啟動並執行程式都是一個進程。每個進程包含一到多個線程。進程也可能是整個程式或者是部分程式的動態執行。線程是一組指令的集合,或者是程式的特殊段,它可以在程式裡獨立執行。也可以把它理解為代碼啟動並執行上下文。所以線程基本上是輕量級的進程,它負責在單個程式裡執行多任務。通常由作業系統負責多個線程的調度和執行

線程的優先順序

  • 優先順序的取值為1-10(數值越高優先順序越高)。
  • Public final int getPriority();  得到線程優先順序的數值。
  • Public final void setPriority(int newPriority);修改線程的優先順序。
  • 註:優先順序高不代表該線程就一定先運行,只能代表該線程先啟動並執行可能型比較大。

控制線程周期常用的方法

  • Wait()釋放CPU的執行權,釋放鎖。
  • Notify()回到wait前的狀態。
  • Yied()讓線程臨時暫停。(讓線程將資源釋放出來)
  • Join()讓該線程強行加入執行。
  • SetDaemon(true)設定該線程為後台線程(當前台線程結束時,後台線程一定會一起結束)。
  • 註:結束線程原理就是讓run方法結束,所以只要控制run的流程即可。

為什麼要線程同步

  • 線程間共用代碼和資料可以節省系統開銷,提高效率。但也同時會導致“資料存取違規”。如何?線程間有機互動,並確保共用資源在某時只能被一個線程訪問,就是線程同步。
  •   多個線程間共用的資料稱為臨界資源。
多線程的同步與互斥:方式一:鎖
  • 在主線程中初始化鎖為解鎖狀態
    • pthread_mutex_t mutex;
    • pthread_mutex_init(&mutex, NULL);
  • 在編譯時間初始化鎖為解鎖狀態
    • 鎖初始化 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  • 訪問對象時的加鎖操作與解鎖操作
    • 加鎖 pthread_mutex_lock(&mutex)
    • 釋放鎖 pthread_mutex_unlock(&mutex)

互斥鎖

  •   每個對象都對應一個互斥鎖標記,可以保證在某一時刻只能有一個線程訪問該對象。
  •   互斥鎖的關鍵字 synchronized 可以寫在某個方法上(代表鎖調用該方法的對象);  可以括在要鎖的語句外。
  • 好處:解決了安全執行緒的問題
  • 弊端:降低了運行效率(判斷鎖,且不能共用資訊);容易出現死結。

死結:

  • 兩個線程A,B用到同一個對象s(s為共用資源),且線程A在執行中要用到B運行後所創造條件。在這種前提下A先開始運行,進入同步塊後,對象s被鎖定,接著線程A因等待B運行結束而進入阻塞狀態,於是B開始運行,但因無法訪問對象s,線程B也進入阻塞狀態,等待s被線程A解鎖。最終的結果:兩個線程互相等待,都無法運行。

方式二:訊號量

鎖有一個很明顯的缺點,那就是它只有兩種狀態:鎖定與不鎖定。

訊號量本質上是一個非負數的整數計數器,它也被用來控制對公用資源的訪問。當公用資源增加的時候,調用訊號量增加函數sem_post()對其進行增加,當公用資源減少的時候,調用函數sem_wait()來減少訊號量。其實,我們是可以把鎖當作一個0-1訊號量的。

它們是在/usr/include/semaphore.h中進行定義的,訊號量的資料結構為sem_t, 本質上,它是一個long型整數

相關函數

在使用semaphore之前,我們需要先引入標頭檔#include <semaphore.h>

  • 初始化訊號量: int sem_init(sem_t *sem, int pshared, unsigned int value);
    • 成功返回0,失敗返回-1
    • 參數
    • sem:指向訊號量結構的一個指標
    • pshared: 不是0的時候,該訊號量在進程間共用,否則只能為當前進程的所有線程們共用
    • value:訊號量的初始值
  • 訊號量減1操作,當sem=0的時候該函數會堵塞 int sem_wait(sem_t *sem);
    • 成功返回0,失敗返回-1
    • 參數
    • sem:指向訊號量的一個指標
  • 訊號量加1操作 int sem_post(sem_t *sem);
    • 參數與返回同上
  • 銷毀訊號量 int sem_destroy(sem_t *sem);
    • 參數與返回同上

訊號量和鎖的區別

訊號量用在多線程多任務同步的,一個線程完成了某一個動作就通過訊號量告訴別的線程,別的線程再進行某些動作(大家都在semtake的時候,就阻塞在 哪裡)。而互斥鎖是用在多線程多任務互斥的,一個線程佔用了某一個資源,那麼別的線程就無法訪問,直到這個線程unlock,其他的線程才開始可以利用這 個資源。比如對全域變數的訪問,有時要加鎖,操作完了,在解鎖。有的時候鎖和訊號量會同時使用的”

也就是說,訊號量不一定是鎖定某一個資源,而是流程上的概念,比如:有A,B兩個線程,B線程要等A線程完成某一任務以後再進行自己下面的步驟,這個任務 並不一定是鎖定某一資源,還可以是進行一些計算或者資料處理之類。而線程互斥量則是“鎖住某一資源”的概念,在鎖定期間內,其他線程無法對被保護的資料進 行操作。在有些情況下兩者可以互換。

兩者之間的區別:

範圍

訊號量: 進程間或線程間(Linux僅線程間的無名訊號量pthread semaphore)

互斥鎖: 線程間

上鎖時 

訊號量: 只要訊號量的value大於0,其他線程就可以sem_wait成功,成功後訊號量的value減一。若value值不大於0,則sem_wait使得線程阻塞,直到sem_post釋放後value值加一,但是sem_wait返回之前還是會將此value值減一

互斥鎖: 只要被鎖住,其他任何線程都不可以訪問被保護的資源

以下是號誌(量)的一些概念:

號誌與互斥鎖和條件變數的主要不同在於”燈”的概念,燈亮則意味著資源可用,燈滅則意味著不可用。如果說後兩中同步方式側重於”等待”操作,即資 源停用話,號誌機制則側重於點燈,即告知資源可用;

沒有等待線程的解鎖或激發條件都是沒有意義的,而沒有等待燈亮的線程的點燈操作則有效,且能保持 燈亮狀態。當然,這樣的操作原語也意味著更多的開銷。

號誌的應用除了燈亮/燈滅這種二元燈以外,也可以採用大於1的燈數,以表示資源數大於1,這時可以稱之為多元燈。

 原子操作

在多進程(線程)訪問共用資源時,能夠確保所有其他的進程(線程)都不在同一時間內訪問相同的資源。原子操作(atomic operation)是不需要synchronized,這是Java多線程編程的老生常談了。所謂原子操作是指不會被線程調度機制打斷的操作;這種操作一旦開始,就一直運行到結束,中間不會有任何 context switch (切換到另一個線程)。通常所說的原子操作包括對非long和double型的primitive進行賦值,以及返回這兩者之外的primitive。之所以要把它們排除在外是因為它們都比較大,而JVM的設計規範又沒有要求讀操作和賦值操作必須是原子操作(JVM可以試著去這麼作,但並不保證)。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.