## 21.多线程
通常,程序是逐行读取的,并由计算机逐步执行。 在任何给定的时间点,计算机仅执行一条指令 1。 随着技术的进步,可以同时执行许多指令,这种同时执行许多操作的过程称为多处理或并行处理。 想象一下,你要吃 5 个披萨。 你需要花费很长时间。 如果你也可以带来你的朋友,那么你的人们可以分担负担。 如果你可以组成一个由 20 个人组成的小组,那么吃 5 个披萨就变得像吃零食一样容易。 完成分配任务所需的时间大大减少。
在 Ruby 编程中,你可以使解释器以并行方式执行代码。 并行执行代码的过程称为多线程。 要显示多线程的工作方式,请在文本编辑器中键入以下程序并执行。
```rb
#!/usr/bin/ruby
# multithreading.rb
a = Thread.new{
i = 1
while i<=10
sleep(1)
puts i
i += 1
end
}
puts "This code comes after thread"
a.join
```
这是程序输出
```rb
This code comes after thread
1
2
3
4
5
6
7
8
9
10
```
与其他程序不同,此程序将花费 10 秒钟执行。 看一下程序和输出。 `puts "This code comes after thread"`之后
```rb
a = Thread.new{
i = 1;
while i<=10
sleep(1)
puts i
i += 1
end
}
```
但是它首先被打印。 在上面显示的语句中,我们创建一个名为 a 的新线程,在该线程中,我们使用`while`循环从 1 到 10 进行打印。请注意,我们调用了一个名为`sleep(1)`的函数,该函数可使进程休眠或保持空闲一秒钟。 创建了一个线程,当线程运行时,Ruby 解释器检查主线程,并且遇到`puts "This code comes after thread"`,因此它在执行我们创建的新线程 a 的同时打印出字符串并并行执行,因此 1 到 10 在插入`sleep(1)`时被打印,每个循环执行大约需要 1 秒钟。 因此,在 10 秒钟后,线程 a 完成。
`a.join`告诉 Ruby 解释器等待线程完成执行。 一旦执行了`a.join`(如果有)之后的语句,线程 a 的执行结束。 由于之后没有语句,程序终止。
这是另一个清楚说明多线程的程序。 仔细检查该程序,尝试了解它的工作原理,稍后我将对其进行解释
```rb
#!/usr/bin/ruby
# multithreading_1.rb
def func1
i=0
while i<=2
puts "func1 at: #{Time.now}"
sleep(2)
i=i+1
end
end
def func2
j=0
while j<=2
puts "func2 at: #{Time.now}"
sleep(1)
j=j+1
end
end
puts "Started At #{Time.now}"
t1 = Thread.new{func1()}
t2 = Thread.new{func2()}
t1.join
t2.join
puts "End at #{Time.now}"
```
看一下突出显示的代码,我们创建了两个线程`t1`和`t2`。 在线程`t1`中,我们称为方法`func1()`,在线程`t2`中,我们称为方法`func2()`,这样做是同时执行`func1()`和`func2()`。 执行后,输出结果将如下所示: <sup class="footnote">[ [51](#_footnotedef_51 "View footnote.") ]</sup>
```rb
Started At Sun Apr 25 09:37:51 +0530 2010
func1 at: Sun Apr 25 09:37:51 +0530 2010
func2 at: Sun Apr 25 09:37:51 +0530 2010
func2 at: Sun Apr 25 09:37:52 +0530 2010
func1 at: Sun Apr 25 09:37:53 +0530 2010
func2 at: Sun Apr 25 09:37:53 +0530 2010
func1 at: Sun Apr 25 09:37:55 +0530 2010
End at Sun Apr 25 09:37:57 +0530 2010
```
从输出中可以看到,`func1`和`func2`打印的输出是隔行扫描的,这证明它们是并行执行的。 请注意,在`func1`中,通过提供`sleep(2)`使线程休眠 2 秒,在`func2`中,通过提供`sleep(1)`使线程休眠 1 秒。
我对 [multithreading_1.rb](code/multithreading_1.rb) 进行了一些小的更改,以产生 [multithreading_2.rb](code/multithreading_2.rb) ,该结果几乎与 [multithreading_1.rb](code/multithreading_1.rb) 的结果相同,因此这里是其代码:
```rb
#!/usr/bin/ruby
# multithreading_2.rb
def func name, delay
i=0
while i<=2
puts "#{name} #{Time.now}"
sleep delay
i=i+1
end
end
puts "Started At #{Time.now}"
t1 = Thread.new{func "Thread 1:", 2}
t2 = Thread.new{func "Thread 2:", 3}
t1.join
t2.join
puts "End at #{Time.now}"
```
我没有使用两个函数`func1`和`func2`,而是编写了一个名为`func`的函数,该函数接受名称和时间延迟作为输入。 其中的循环会打印出传递的名称和执行该语句的时间。 注意这些声明
```rb
t1 = Thread.new{func "Thread 1:", 2}
t2 = Thread.new{func "Thread 2:", 3}
```
我们创建两个线程`t1`和`t2`。 在线程`t1`中,我们调用函数`func`并传递名称`Thread 1:`并告诉它休眠 2 秒钟。 在线程`t2`中,我们调用相同的`func`,并传递与`Thread 2:`相同的名称,并在每次循环迭代中告诉它休眠 3 秒。 并在执行程序时产生以下输出
```rb
Started At Sun Apr 25 09:44:36 +0530 2010
Thread 1: Sun Apr 25 09:44:36 +0530 2010
Thread 2: Sun Apr 25 09:44:36 +0530 2010
Thread 1: Sun Apr 25 09:44:38 +0530 2010
Thread 2: Sun Apr 25 09:44:39 +0530 2010
Thread 1: Sun Apr 25 09:44:40 +0530 2010
Thread 2: Sun Apr 25 09:44:42 +0530 2010
End at Sun Apr 25 09:44:45 +0530 2010
```
这与 [multithreading_1.rb](code/multithreading_1.rb) 产生的输出非常相似。
### 21.1。 线程变量的范围
线程可以访问主进程中的变量,以以下程序( [thread_variables.rb](code/thread_variables.rb) )为例
```rb
#!/usr/bin/ruby
# thread_variables.rb
variable = 0
puts "Before thread variable = #{variable}"
a = Thread.new{
variable = 5
}
a.join
puts "After thread variable = #{variable}"
```
输出量
```rb
Before thread variable = 0
After thread variable = 5
```
输入程序并运行。 它将产生上面显示的结果。 从程序中可以看到,在创建线程之前,我们将名为`variable`的变量初始化为 0。 在线程内部,我们将`variable`的值更改为 5。在线程块之后,我们输出的变量值现在为 5。该程序向我们展示了你可以访问和操作在主线程中声明的变量。
现在让我们看看是否可以在线程范围之外访问在线程内部创建的变量? 键入以下程序( [thread_variables_1.rb](code/thread_variables_1.rb) )并执行
```rb
#!/usr/bin/ruby
# thread_variables_1.rb
variable = 0
puts "Before thread variable = #{variable}"
a = Thread.new{
variable = 5
thread_variable = 72
puts "Inside thread thread_variable = #{thread_variable}"
}
a.join
puts "=================\nAfter thread\nvariable = #{variable}"
puts "thread_variable = #{thread_variable}"
```
Output
```rb
Before thread variable = 0
Inside thread thread_variable = 72
=================
After thread
variable = 5
thread_variables_1.rb:13: undefined local variable or method `thread_variable' for main:Object (NameError)
```
在上面的程序中,我们看到我们在线程`a`中创建了一个名为 thread_variable 的变量,现在我们尝试在以下行中对其进行访问:
```rb
puts "thread_variable = #{thread_variable}"
```
如你所见,该程序/ Ruby 解释器吐出错误的输出如下所示:
```rb
thread_variables_1.rb:13: undefined local variable or method `thread_variable' for main:Object (NameError)
```
它说有一个名为`thread_variable`的未定义局部变量或方法。 这意味着主线程中的语句无法访问线程`a`中声明的变量。 因此,从前两个示例可以清楚地看出,线程可以访问主线程中声明的变量,而线程的作用域中声明的变量不能被主作用域中的语句访问。
### 21.2。 线程排除
假设有两个共享同一资源的线程,则将该资源作为变量。 假设第一个线程修改了变量,而第二个线程尝试访问变量时,会发生什么呢? 答案很简单明了,尽管程序运行似乎没有错误,但你可能无法获得理想的结果。 这个概念很难理解,让我尝试用一个例子来解释它。 输入并执行 [thread_exclusion.rb](code/thread_exclusion.rb)
```rb
#!/usr/bin/ruby
# thread_exclusion.rb
x = y = 0
diff = 0
Thread.new {
loop do
x+=1
y+=1
end
}
Thread.new {
loop do
diff += (x-y).abs
end
}
sleep(1) # Here main thread is put to sleep
puts "difference = #{diff}"
```
Output
```rb
difference = 127524
```
仔细阅读程序。 在开始任何线程之前,我们将三个变量`x`,`y`和 diff 分配给值 0。然后在第一个线程中,我们开始一个循环,在该循环中我们增加`x`和`y`的值。 在另一个线程中,我们找到`x`和`y`之间的区别,并将其保存在名为`diff`的变量中。 在第一个线程中`x`和`y`同时增加,因此语句`diff += (x-y).abs`不应对变量`diff`添加任何内容,因为`x`和`y`始终相等,并且它们的差值始终为零,因此 它们的差的绝对值也将始终为零。
在此程序中,我们不等待线程加入(因为它们包含无限循环),我们使用命令`sleep(1)`使主循环休眠一秒钟,然后在以下语句中打印 diff 的值
```rb
puts "difference = #{diff}"
```
人们会期望该值为零,但我们得到的值为 127524,在你的计算机中,该值可能会有所不同,因为它取决于机器速度,运行的处理器和其他参数。 但是道德是`diff`应该为零有一定价值,为什么呢?
我们在第一个循环中看到`x`递增,然后`y`递增,假设`x`的值为 5,y 值为 4,即`x`刚在语句中递增 `x += 1`,现在 Ruby 解释器将要读取并执行`y += 1`,这将使`y`从 4 变为 5。在此阶段,第二个线程由计算机执行。 所以在声明中
```rb
diff += (x-y).abs
```
将`x`设置为 5,将`y`设置为 4 将意味着`diff`将递增 1。以类似的方式,当主循环休眠一秒钟时,我们创建的两个线程将完成数千个循环周期, 因此`diff`的值将显着增加。 这就是为什么我们将 diff 的值当作一个大数字来获取的原因。
好了,我们已经看到了如何不以错误的方式编写程序,现在让我们看看如何以正确的方式编写程序。 现在,我们的任务是同步已创建的两个线程,以便当另一个线程处于某个繁忙进程的中间时,一个线程不会访问其他线程资源。 为此,我们将使用互斥体,即互斥。 在文本编辑器中键入以下程序 [thread_exclusion_1.rb](code/thread_exclusion_1.rb) 并执行它
```rb
#!/usr/bin/ruby
# thread_exclusion_1.rb
require 'thread'
mutex = Mutex.new
x = y = 0
diff = 0
Thread.new {
loop do
mutex.synchronize do
x+=1
y+=1
end
end
}
Thread.new {
loop do
mutex.synchronize do
diff += (x-y).abs
end
end
}
sleep(1) # Here main thread is put to sleep
puts "difference = #{diff}"
```
Output
```rb
difference = 0
```
如上所示,我们将输出显示为`difference = 0`,这意味着`diff`变量为零。 某些原因阻止了第二个线程在第一个线程繁忙时访问第一个线程中的`x`和`y`。 这两个线程如何学会正确地共享资源。 仔细研究代码,我们看到我们通过键入包含了一个线程包
```rb
require 'thread'
```
接下来,我们使用以下命令创建了一个名为 Mutex 的 Mutex 变量。
```rb
mutex = Mutex.new
```
那么代码就和往常一样,除了线程内部。 让我们看一下第一个线程
```rb
Thread.new {
loop do
mutex.synchronize do
x += 1
y += 1
end
end
}
```
我们看到`x += 1`和`y += 1`语句包含在`mutex.synchronize`块中。 同样,计算`x`和`y`之差的代码也包含在`mutex.synchronize`块中,如下所示:
```rb
Thread.new {
loop do
mutex.synchronize do
diff += (x-y).abs
end
end
}
```
通过这样做,我们告诉计算机这两个线程共享一个公共资源,并且只有另一个线程释放该资源时,一个线程才能访问该资源。 这样,当在`diff += (x-y).abs`中计算出差(`diff`)时,`x`和`y`的值将始终相等,因此 diff 永远不会增加并且永远保持为零。
### 21.3。 死锁
你是否曾经站在队列中,或等待过什么。 我们都在机场等了一个地方,以便对我们的行李进行扫描和清理。 可以说行李扫描机出故障了,你被困在机场。 预计你将参加重要的公司会议,并且有重要的演讲,并且你必须发表重要的讲话。 由于行李扫描仪发生故障,因此你所需要的资源不可用,并且你掌握了在会议中进行交谈的关键知识,因此会议忙得不可开交。 会议中的一个可能会答应带他的家人去看电影,他可能会在延迟的会议之后回来很晚,因此一切都搞砸了。
想象一下,行李扫描仪,你,一个必须听见你的会议的人,是 Ruby 程序的线程。 由于行李扫描仪不会释放资源(你的行李),因此你的流程将被延迟,并且由于延迟,许多其他依赖于你的流程也会延迟。 这种情况称为死锁。 它也发生在 Ruby 程序中。 每当出现这种情况时,人们就会等待而不是向前冲。 你等待行李被放行,公司等待你的到来,芒家族等待他将其带到电影中。 如果不等人们赶时间,就会造成混乱。 Ruby 具有避免这种混乱并处理这种死锁的机制。 我们使用一种称为条件变量的东西。 看下面的程序( [thread_condition_variable.rb](code/thread_condition_variable.rb) ),键入并执行它。
```rb
#!/usr/bin/ruby
# thread_condition_variable.rb
require 'thread'
mutex = Mutex.new
c = ConditionVariable.new
a = Thread.new {
mutex.synchronize {
puts "Thread a now waits for signal from thread b"
c.wait(mutex)
puts "a now has the power to use the resource"
}
}
puts "(Now in thread b....)"
b = Thread.new {
mutex.synchronize {
puts "Thread b is using a resource needed by a, once its done it will signal to a"
sleep(4)
c.signal
puts "b Signaled to a to acquire resource"
}
}
a.join
b.join
```
Output
```rb
Thread a now waits for signal from thread b
(Now in thread b....)
Thread b is using a resource needed by a, once its done it will signal to a
b Signaled to a to acquire resource
a now has the power to use the resource
```
仔细研究程序并输出。 查看输出。 首先,执行线程`a`中的语句,并打印出线程`a`正在等待线程`b`发出信号以继续执行该语句。 参见线程`a`,我们编写了代码`c.wait(mutex)`,其中`c`是代码中声明的条件变量,如下所示:
```rb
c = ConditionVariable.new
```
所以现在线程 a 等待,现在在线程`b 中遇到以下行时,执行集中在线程 b 上
```rb
puts "Thread b is using a resource needed by a, once its done it will signal to a"
```
它打印出线程`b`正在使用`a`所需的某些资源,下一个线程`b`休眠 4 秒,因为我们在其中指定了`sleep(4)`。 可以避免使用`sleep`语句,我给出了`sleep`,因为在读者执行程序时,它使他等待并感到条件变量的工作原理。
然后,在 4 秒钟后,线程`b`向线程`a`发出信号,其等待可以使用语句`c.signal`结束。 现在,线程 a 接收信号并可以执行其其余语句,即在`c.signal`之后,线程`a`和线程`b`可以同时执行。
### 21.4。 创建多个线程
假设你有一种情况,必须创建许多线程,并且必须以优雅的方式完成,说一种情况可能会出现,你甚至不知道可以创建多少个线程,但是必须创建它们并且 程序应该等待他们加入然后退出,所以让我们看看如何编写代码。
因此,在你的文本编辑器中键入以下程序并运行它
```rb
# many_threads.rb
def launch_thread string
thread = Thread.new do
3.times do
puts string
sleep rand(3)
end
end
return thread
end
threads = []
threads << launch_thread("Hi")
threads << launch_thread("Hello")
threads.each {|t| t.join}
```
Output
```rb
Hi
Hello
Hello
Hello
Hi
Hi
```
如果你没有获得如上所述的确切输出,请不要担心,因为程序中存在一些随机性。 让我解释一下该程序,以便你看清楚它。
首先,我们声明一个将容纳线程的数组,如下所示
```rb
threads = []
```
接下来,我们将使用函数`launch_thread`将值放入线程数组,如下所示
```rb
threads << launch_thread("Hi")
```
让我们分析`launch_thread`函数中发生的事情,首先我们有一个如下所示的函数
```rb
def launch_thread string
…....
end
```
我们从函数返回一个名为`thread`的变量
```rb
def launch_thread string
return thread
end
```
我们将新创建的线程分配给变量线程
```rb
def launch_thread string
thread = Thread.new do
end
return thread
end
```
我们在新创建的线程中放入一些代码
```rb
def launch_thread string
thread = Thread.new do
3.times do
puts string
sleep rand(3)
end
end
return thread
end
```
而已。 简而言之,我们创建线程,在其中运行代码,然后将其返回并存储在`threads`数组中。 这行也发生了同样的事情
```rb
threads << launch_thread("Hello")
```
现在,我们必须等待每个线程加入主程序(或主线程)。 因此,我们编写了如下所示的连接代码
```rb
threads.each {|t| t.join}
```
这将等待所有线程完成并与主代码联接。
因此,我们编写了一个程序,该程序可以创建所需的任意数量的线程(在上面的示例中为两个),所有线程将被收集到一个数组中,主程序将等待所有线程完成并与之连接,然后 将退出。
现在看看 [many_threads_1.rb](code/many_threads_1.rb) 和 [many_threads_2.rb](code/many_threads_2.rb) ,执行它们并向自己解释它们如何工作。 最好为他们写一个好的解释并邮寄给我,以便我可以将其放在这本书中。
```rb
# many_threads_1.rb
def launch_thread string
thread = Thread.new do
3.times do
puts string
sleep rand(3)
end
end
return thread
end
threads = []
4.times do |i|
threads << launch_thread("Thread #{i}")
end
threads.each {|t| t.join}
```
```rb
# many_threads_2.rb
def launch_thread string
thread = Thread.new do
3.times do
puts string
sleep rand(3)
end
end
return thread
end
threads = []
puts "How many threads should run?"
count = gets.to_i
count.times do |i|
threads << launch_thread("Thread #{i}")
end
threads.each {|t| t.join}
```
### 21.5。 线程异常
每当程序运行时发生异常,并且如果异常处理不当,程序就会终止。 让我们看看线程中有异常时会发生什么。 在文本编辑器中键入代码 [thread_exception_true.rb](code/thread_exception_true.rb) 并执行它。
```rb
#!/usr/bin/ruby
# thread_exception_true.rb
t = Thread.new do
i = 5
while i >= -1
sleep(1)
puts 25 / i
i -= 1
end
end
t.abort_on_exception = true
sleep(10)
puts "Program completed"
```
Output
```rb
5
6
8
12
25
thread_exception_true.rb:8:in `/': divided by 0 (ZeroDivisionError)
from thread_exception_true.rb:8
from thread_exception_true.rb:4:in `initialize'
from thread_exception_true.rb:4:in `new'
from thread_exception_true.rb:4
```
注意,在程序中我们创建了一个名为`t`的线程,如果你很安静,则程序中没有`t.join`。 与其等待线程加入,不如等待足够长的时间来完成线程。 为了使线程完成,我们使用语句`sleep(10)`等待 10 秒。
注意我们设置的`t.abort_on_exception = true`行,如果线程`t`中引发异常,则程序必须中止。 现在让我们分析线程`t`中的内容。 线程`t`包含以下代码
```rb
t = Thread.new do
i = 5
while i >= -1
sleep(1)
puts 25 / i
i -= 1
end
end
```
注意,我们将 25 除以`i`,然后得出除法结果。 `i`在每次循环迭代中递减 1,因此,当`i`变为零且被其除以 25 时,它将引发异常。 因此,在循环的第六次迭代中,将 25 除以零,引发异常,并通过吐出以下内容停止程序
```rb
thread_exception_true.rb:8:in `/': divided by 0 (ZeroDivisionError)
from thread_exception_true.rb:8
from thread_exception_true.rb:4:in `initialize'
from thread_exception_true.rb:4:in `new'
from thread_exception_true.rb:4
```
发生这种情况是因为我们已将`t.abort_on_exception`设置为`true`(请参见突出显示的代码)。 如果将其设置为`false`会发生什么。 看一下程序 [thread_exception_false.rb](code/thread_exception_false.rb) 。 在程序中,我们将`t.abort_on_exception`设置为`false`。 在文本编辑器中键入程序并运行
```rb
#!/usr/bin/ruby
# thread_exception_false.rb
t = Thread.new do
i = 5
while i >= -1
sleep(1)
puts 25 / i
i -= 1
end
end
t.abort_on_exception = false
sleep(10)
puts "Program completed"
```
看一下输出
```rb
5
6
8
12
25
Program completed
```
从输出中可以看到,没有异常发生的痕迹 4。 执行线程`t`之后的代码,我们得到显示为`Program Completed`的输出。 这是因为我们将`abort_on_exception`设置为`false`。
你可以从最后两个程序中看到我们尚未使用`t.join`,相反,我们已经等待了足够长的时间以终止线程。 之所以这样,是因为一旦我们将线程(导致)与父线程(在这种情况下为主线程)连接在一起,子线程中出现的异常就会传播到父线程/等待线程,因此`abort_on_exception`甚至没有作用 设置为 false。 因此,每当异常发生时,它就会反映在我们的终端上。
### 21.6。 线程类方法
你可以使用某些线程方法来操纵线程的属性。 这些在下面列出。 如果你一点都不懂,那就不用担心。
<colgroup><col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"></colgroup>
| 斯诺 | 方法 | 它能做什么 |
| --- | --- | --- |
| 1。 | Thread.abort_on_exception | 返回异常情况下全局中止的状态。 默认值为 false。 设置为 true 时,如果任何线程中引发异常,将导致所有线程中止(进程将退出(0))。 |
| 2。 | Thread.abort_on_exception = | 设置为 true 时,如果引发异常,则所有线程将中止。 返回新状态。 |
| 3。 | 线程临界 | 返回全局线程严重条件的状态。 |
| 4。 | Thread.critical = | 设置全局线程紧急条件的状态并返回。 设置为 true 时,禁止调度任何现有线程。 不会阻止新线程的创建和运行。 某些线程操作(例如停止或杀死线程,在当前线程中休眠以及引发异常)可能导致即使在关键部分中也要调度线程。 |
| 5, | 线程电流 | 返回当前正在执行的线程。 |
| 6。 | 线程退出 | 终止当前正在运行的线程并安排另一个线程运行。 如果此线程已被标记为已终止,则 exit 返回该线程。 如果这是主线程或最后一个线程,请退出进程。 |
| 7 | Thread.fork {块} | Thread.new 的同义词 |
| 8。 | Thread.kill(aThread) | 使给定的 aThread 退出 |
| 9。 | 线程列表 | 返回所有可运行或已停止线程的 Thread 对象数组。 线。 |
| 10。 | 线程主 | 返回该进程的主线程。 |
| 11。 | Thread.new([arg] *){| args | 阻止 | 创建一个新线程以执行块中给出的指令,然后开始运行它。 传递给 Thread.new 的所有参数都传递给该块。 |
| 12 | 线程传递 | 调用线程调度程序以将执行传递给另一个线程。 |
| 13 | Thread.start([args] *){| args | 阻止 | 基本上与 Thread.new 相同。 但是,如果 Thread 类是子类,则在该子类中调用 start 不会调用该子类的 initialize 方法。 |
| 14。 | 线程停止 | 停止当前线程的执行,使其进入睡眠状态,并计划另一个线程的执行。 将关键条件重置为 false |
### 21.7。 线程实例方法
由于 Ruby 中的所有内容都是对象,因此 ia 线程也是对象。 与许多对象一样,线程具有可以调用以访问或设置线程中的属性的函数或方法。 下面列出了一些功能及其用途(thr 是 Thread 类的实例变量):
<colgroup><col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"></colgroup>
| Sno. | Method | What it does |
| --- | --- | --- |
| 1 个 | 活着吗? | 如果线程处于活动状态或睡眠状态,则此方法返回 true。 如果线程已终止,则返回 false。 |
| 2 | 退出 | 杀死或退出线程 |
| 3 | thr.join | 该进程等待线程与创建子线程的进程或线程联接。 子线程完成执行后,主线程在 thr.join 之后执行语句 |
| 4 | 杀伤力 | 相同的广告退出次数 |
| 5 | 优先级 | 获取线程的优先级。 |
| 6 | thr.priority = | 设置线程的优先级。 优先级越高,具有较高编号的线程将具有更高的优先级。 |
| 7 | thr.raise(anException) | 从 thr 引发异常。 呼叫者不必是 thr。 |
| 8 | 运行 | 唤醒 thr,使其有资格进行调度。 如果不在关键部分,则调用调度程序。 |
| 10 | 唤醒 | 将 thr 标记为可进行调度,但是它仍可能在 I / O 上处于阻塞状态。 |
| 11 | 状态 | 返回 thr 的状态:如果 thr 正在睡眠或正在等待 I / O,则进入 sleep;如果 thr 正在执行,则运行;如果 thr 正常终止,则返回 false;如果 thr 终止,则返回 nil。 |
| 12 | 停止吗? | 等待 thr 通过 Thread.join 完成并返回其值。 |
| 13 | thr [aSymbol] | 属性参考-使用符号或 aSymbol 名称返回线程局部变量的值。 如果指定的变量不存在,则返回 nil。 |
| 14 | thr [aSymbol] = | 属性分配-使用符号或字符串设置或创建线程局部变量的值。 |
| 15 | thr.abort_on_exception | 返回 thr 的异常情况中止的状态。 默认值为 false。 |
| 16 | thr.abort_on_exception = | 设置为 true 时,如果 thr 中引发异常,将导致所有线程(包括主程序)中止。 该过程将有效退出(0)。 |
- 前言
- 红宝石
- 先决条件
- 1.安装 Ruby
- 2.在线资源
- 3.入门
- 4.比较与逻辑
- 5.循环
- 6.数组
- 7.哈希和符号
- 8.范围
- 9.功能
- 10.可变范围
- 11.类&对象
- 12.安全导航
- 13.打破大型程序
- 14.结构和 OpenStruct
- 15. Rdoc
- 16. Ruby 样式指南
- 17.模块和混入
- 18.日期和时间
- 19.文件
- 20. Proc,Lambda 和块
- 21.多线程
- 22.异常处理
- 23.正则表达式
- 24.宝石
- 25.元编程
- 26.基准
- 27.测试驱动开发
- 28.观察者模式
- 29.模板模式
- 30.工厂模式
- 31.装饰图案
- 32.适配器模式
- 33.单例模式
- 34.复合模式
- 35.建造者模式
- 36.策略模式
- 赞助商
- 捐
- 人们怎么说
- 版权
- 取得这本书