教程:線程

發表于:2007-07-04來源:作者:點擊數: 標簽:
線程概述 線程(Thread)就是指能在一個程序中處理若干控制流的功能。與OS提供的進程不同的是,線程可以共享內存空間。 Ruby中使用的線程是用戶級線程,由Ruby解釋器進行切換管理。其效率要低于由OS管理線程的效率,且不能使用多個CPU,這確實是它的缺點。但其
線程概述

線程(Thread)就是指能在一個程序中處理若干控制流的功能。與OS提供的進程不同的是,線程可以共享內存空間。

Ruby中使用的線程是用戶級線程,由Ruby解釋器進行切換管理。其效率要低于由OS管理線程的效率,且不能使用多個CPU,這確實是它的缺點。但其優點也很明顯,即可移植性很高。

線程的生成

可以使用Thread.start方法來生成新線程。其用法如下。

Thread.start { .... }

Thread.start生成新線程后,新線程會對迭代程序塊進行判斷。舉個簡單的例子來看一看線程如何運作。

1 Thread.start { 2 while true 3 print "thread 1\n" 4 end 5 } 6 7 while true 8 print "thread 2\n" 9 end

程序運行后“thread1”和“thread2”交替出現,可以看出有兩個無限循環在同時運作。請按下Ctrl-C來終止程序。

線程的操作

線程類的方法如下。

Thread.start {...} Thread.new {...} 生成新線程,并對迭代程序塊進行判斷。返回新生成的線程對象。new是start的別名。 Thread.current 返回當前運行的線程對象。 Thread.exit 終止當前運行的線程對象。 Thread.join thread 掛起現在的線程,直到指定線程運行結束為止。 Thread.kill thread 終止指定線程的運行。 Thread.pass 將控制權顯式地交給其他可運行的線程。 Thread.stop 掛起現在的線程,直到其他線程運行thread#run為止。 Thread#exit 終止receiver線程。 Thread#run 重新開啟receiver線程。 Thread#stop 掛起receiver線程。 Thread#status 若receiver線程存在則返回真。若線程因錯誤而終止,則引發那個錯誤。 Thread#value 返回判斷receiver迭代程序塊的結果。若判斷迭代程序塊的過程尚未完成,則等到該線程終止為止。 線程間的同步

因為線程共享內存空間,所以使用普通的變量就可完成線程間的數據交換工作。但是為了使操作的時機得當,有必要進行同步。若同步失敗會引起各種問題,如可能會一直等一個不可能出現的數據而陷入死鎖狀態,或接收了非預期數據導致難以查找的錯誤等等。

Ruby的線程庫提供了兩種同步方法。一種是只負責同步的Mutex,還有一種是兼管數據交接的Queue。若想使用這些庫,需要在程序頭部調用下列內容。

require "thread" Mutex

Mutex是mutual-exclusion lock(互斥鎖)的簡稱。若對Mutex加鎖時發現已經處于鎖定狀態時,線程會掛起直到解鎖為止。

在并行訪問中保護共享數據時,可以使用下列代碼(m是Mutex的實例)。

begin m.lock # 訪問受m保護的共享數據 ensure m.unlock end

Mutex有個synchronize方法可以簡化這一過程。

m.synchronize { # 訪問受m保護的共享數據 }

舉個簡單的例子。

1 require "thread" 2 3 m = Mutex.new 4 v = 0; # 受m保護的數據 5 6 Thread.start { 7 while true 8 m.synchronize { 9 v = v + 100 10 } 11 end 12 } 13 14 while true 15 m.synchronize { 16 v = v - 33 17 } 18 end

若此程序中不使用Mutex加以保護的話,因為時機問題,在一個線程讀取v的數值后還沒來得及進行賦值的時候,另一個線程可能已經改變了v的數值。

Mutex有下列方法。

Mutex.new 生成新的互斥鎖。 Mutex#lock 加鎖。若已經處于加鎖狀態則會一直等待下去,直到解鎖為止。 Mutex#unlock 解鎖。若有其它等鎖的線程則會讓它們通過。 Mutex#synchronize 執行從獲得鎖到解鎖全過程的迭代器。 Mutex#try_lock 獲得鎖。若已處于加鎖狀態,則返回false且不會掛起。 Queue

Queue就像一條讀寫數據的管道。提供數據的線程在一邊寫入數據,而讀取數據的線程則在另一邊讀出數據。若Queue中沒有可供讀取的數據時,讀取數據的線程會掛起等待數據的到來。

下面就是一個使用Queue的簡單程序。

1 require "thread" 2 3 q = Queue.new 4 5 th = Thread.start { 6 while line = q.pop 7 print line 8 end 9 } 10 11 while gets 12 q.push $_ 13 end 14 q.push nil # 終止標記 15 th.join

本程序中,一個線程讀入一行之后,另一個線程就輸出它。若把第3行改成數組,即“q = []”后,線程間失去同步,則程序無法正確運作。

Queue有下列方法。

Queue.new 生成新的Queue。 Queue.empty? 若Queue為空則返回真。 Queue.push value 向Queue添加value。 Queue.pop [non_block] 從Queue中取出數據。若參數non_block被指定為非假值而且Queue為空時,則引發錯誤。其他情況下,若Queue為空時,讀取數據的線程會被掛起直到有新數據加入。 例題

讓我們來看一看在并行處理編程領域中非常有名的“哲學家就餐”問題。

“哲學家就餐”問題就是指在下述情況下,哲學家如何取得同步的問題。

有N位哲學家圍坐在圓桌旁。圓桌中間放著盛滿意大利面條的大盤子。另有N把叉子分別放在每位哲學家身旁。哲學家繼續思考問題,若覺得餓就會拿起兩旁的叉子就餐。吃完后就將叉子放回去。這些哲學家都是紳士,即使很餓也會等到兩旁都有叉子可用之后才會就餐。

運行程序后會依次顯示當前的狀態。各個字符所代表的意義如下。

o: 正在思考問題的哲學家 *: 正在工作的哲學家 -: 無人使用的叉子 |: 正被使用的叉子

哲學家思考的時間和就餐的時間由隨機數決定。

1 # 2 # The Dining Philosophers - thread example 3 # 4 require "thread" 5 6 N=7 # number of philosophers 7 $forks = [] 8 for i in 0..N-1 9 $forks[i] = Mutex.new 10 end 11 $state = "-o"*N 12 13 def wait 14 sleep rand(20)/10.0 15 end 16 17 def think(n) 18 wait(); 19 end 20 21 def eat(n) 22 wait(); 23 end 24 25 def philosopher(n) 26 while true 27 think n 28 $forks[n].lock 29 if not $forks[(n+1)%N].try_lock 30 $forks[n].unlock # avoid deadlock 31 next 32 end 33 $state[n*2] = ?|; 34 $state[(n+1)%N*2] = ?|; 35 $state[n*2+1] = ?*; 36 print $state, "\n" 37 eat(n) 38 $state[n*2] = ?-; 39 $state[(n+1)%N*2] = ?-; 40 $state[n*2+1] = ?o; 41 print $state, "\n" 42 $forks[n].unlock 43 $forks[(n+1)%N].unlock 44 end 45 end 46 47 for i in 0..N-1 48 Thread.start{philosopher(i)} 49 sleep 0.1 50 end 51 sleep 52 exit

原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97