1# Thread and Fiber 2 3assert_equal %q{ok}, %q{ 4 Thread.new{ 5 }.join 6 :ok 7} 8assert_equal %q{ok}, %q{ 9 Thread.new{ 10 :ok 11 }.value 12} 13assert_equal %q{20100}, %q{ 14 v = 0 15 (1..200).map{|i| 16 Thread.new{ 17 i 18 } 19 }.each{|t| 20 v += t.value 21 } 22 v 23} 24assert_equal %q{5000}, %q{ 25 5000.times{|e| 26 (1..2).map{ 27 Thread.new{ 28 } 29 }.each{|e| 30 e.join() 31 } 32 } 33} 34assert_equal %q{5000}, %q{ 35 5000.times{|e| 36 (1..2).map{ 37 Thread.new{ 38 } 39 }.each{|e| 40 e.join(1000000000) 41 } 42 } 43} 44assert_equal %q{5000}, %q{ 45 5000.times{ 46 t = Thread.new{} 47 while t.alive? 48 Thread.pass 49 end 50 } 51} 52assert_equal %q{100}, %q{ 53 100.times{ 54 Thread.new{loop{Thread.pass}} 55 } 56} 57assert_equal %q{ok}, %q{ 58 Thread.new{ 59 :ok 60 }.join.value 61} 62assert_equal %q{ok}, %q{ 63 begin 64 Thread.new{ 65 raise "ok" 66 }.join 67 rescue => e 68 e 69 end 70} 71assert_equal %q{ok}, %q{ 72 ans = nil 73 t = Thread.new{ 74 begin 75 sleep 0.5 76 ensure 77 ans = :ok 78 end 79 } 80 Thread.pass 81 t.kill 82 t.join 83 ans 84} 85assert_equal %q{ok}, %q{ 86 t = Thread.new{ 87 sleep 88 } 89 sleep 0.1 90 t.raise 91 begin 92 t.join 93 :ng 94 rescue 95 :ok 96 end 97} 98assert_equal %q{ok}, %q{ 99 t = Thread.new{ 100 loop{} 101 } 102 Thread.pass 103 t.raise 104 begin 105 t.join 106 :ng 107 rescue 108 :ok 109 end 110} 111assert_equal %q{ok}, %q{ 112 t = Thread.new{ 113 } 114 Thread.pass 115 t.join 116 t.raise # raise to exited thread 117 begin 118 t.join 119 :ok 120 rescue 121 :ng 122 end 123} 124assert_equal %q{run}, %q{ 125 t = Thread.new{ 126 loop{} 127 } 128 st = t.status 129 t.kill 130 st 131} 132assert_equal %q{sleep}, %q{ 133 t = Thread.new{ 134 sleep 135 } 136 sleep 0.1 137 st = t.status 138 t.kill 139 st 140} 141assert_equal %q{false}, %q{ 142 t = Thread.new{ 143 } 144 t.kill 145 sleep 0.1 146 t.status 147} 148assert_equal %q{[ThreadGroup, true]}, %q{ 149 ptg = Thread.current.group 150 Thread.new{ 151 ctg = Thread.current.group 152 [ctg.class, ctg == ptg] 153 }.value 154} 155assert_equal %q{[1, 1]}, %q{ 156 thg = ThreadGroup.new 157 158 t = Thread.new{ 159 thg.add Thread.current 160 sleep 161 } 162 sleep 0.1 163 [thg.list.size, ThreadGroup::Default.list.size] 164} 165assert_equal %q{true}, %q{ 166 thg = ThreadGroup.new 167 168 t = Thread.new{sleep 5} 169 thg.add t 170 thg.list.include?(t) 171} 172assert_equal %q{[true, nil, true]}, %q{ 173 /a/ =~ 'a' 174 $a = $~ 175 Thread.new{ 176 $b = $~ 177 /b/ =~ 'b' 178 $c = $~ 179 }.join 180 $d = $~ 181 [$a == $d, $b, $c != $d] 182} 183assert_equal %q{11}, %q{ 184 Thread.current[:a] = 1 185 Thread.new{ 186 Thread.current[:a] = 10 187 Thread.pass 188 Thread.current[:a] 189 }.value + Thread.current[:a] 190} 191assert_normal_exit %q{ 192 begin 193 100.times do |i| 194 begin 195 th = Thread.start(Thread.current) {|u| u.raise } 196 raise 197 rescue 198 ensure 199 th.join 200 end 201 end 202 rescue 203 end 204}, '[ruby-dev:31371]' 205 206assert_equal 'true', %{ 207 t = Thread.new { loop {} } 208 begin 209 pid = fork { 210 exit t.status != "run" 211 } 212 Process.wait pid 213 $?.success? 214 rescue NotImplementedError 215 true 216 end 217} 218 219assert_equal 'ok', %{ 220 open("zzz.rb", "w") do |f| 221 f.puts <<-END 222 begin 223 Thread.new { fork { GC.start } }.join 224 pid, status = Process.wait2 225 $result = status.success? ? :ok : :ng 226 rescue NotImplementedError 227 $result = :ok 228 end 229 END 230 end 231 require "./zzz.rb" 232 $result 233} 234 235assert_finish 3, %{ 236 th = Thread.new {sleep 2} 237 th.join(1) 238 th.join 239} 240 241assert_finish 3, %{ 242 require 'timeout' 243 th = Thread.new {sleep 2} 244 begin 245 Timeout.timeout(1) {th.join} 246 rescue Timeout::Error 247 end 248 th.join 249} 250 251assert_normal_exit %q{ 252 STDERR.reopen(STDOUT) 253 exec "/" 254} 255 256assert_normal_exit %q{ 257 (0..10).map { 258 Thread.new { 259 10000.times { 260 Object.new.to_s 261 } 262 } 263 }.each {|t| 264 t.join 265 } 266} 267 268assert_equal 'ok', %q{ 269 def m 270 t = Thread.new { while true; // =~ "" end } 271 sleep 0.1 272 10.times { 273 if /((ab)*(ab)*)*(b)/ =~ "ab"*7 274 return :ng if !$4 275 return :ng if $~.size != 5 276 end 277 } 278 :ok 279 ensure 280 Thread.kill t 281 end 282 m 283}, '[ruby-dev:34492]' 284 285assert_normal_exit %q{ 286 at_exit { Fiber.new{}.resume } 287} 288 289assert_normal_exit %q{ 290 g = enum_for(:local_variables) 291 loop { g.next } 292}, '[ruby-dev:34128]' 293 294assert_normal_exit %q{ 295 g = enum_for(:block_given?) 296 loop { g.next } 297}, '[ruby-dev:34128]' 298 299assert_normal_exit %q{ 300 g = enum_for(:binding) 301 loop { g.next } 302}, '[ruby-dev:34128]' 303 304assert_normal_exit %q{ 305 g = "abc".enum_for(:scan, /./) 306 loop { g.next } 307}, '[ruby-dev:34128]' 308 309assert_normal_exit %q{ 310 g = Module.enum_for(:new) 311 loop { g.next } 312}, '[ruby-dev:34128]' 313 314assert_normal_exit %q{ 315 Fiber.new(&Object.method(:class_eval)).resume("foo") 316}, '[ruby-dev:34128]' 317 318assert_normal_exit %q{ 319 Thread.new("foo", &Object.method(:class_eval)).join 320}, '[ruby-dev:34128]' 321 322assert_equal 'ok', %q{ 323 begin 324 Thread.new { Thread.stop } 325 Thread.stop 326 :ng 327 rescue Exception 328 :ok 329 end 330} 331 332assert_equal 'ok', %q{ 333 begin 334 m1, m2 = Mutex.new, Mutex.new 335 Thread.new { m1.lock; sleep 1; m2.lock } 336 m2.lock; sleep 1; m1.lock 337 :ng 338 rescue Exception 339 :ok 340 end 341} 342 343assert_equal 'ok', %q{ 344 m = Mutex.new 345 Thread.new { m.lock }; sleep 1; m.lock 346 :ok 347} 348 349assert_equal 'ok', %q{ 350 m = Mutex.new 351 Thread.new { m.lock }; m.lock 352 :ok 353} 354 355assert_equal 'ok', %q{ 356 m = Mutex.new 357 Thread.new { m.lock }.join; m.lock 358 :ok 359} 360 361assert_equal 'ok', %q{ 362 m = Mutex.new 363 Thread.new { m.lock; sleep 2 } 364 sleep 1; m.lock 365 :ok 366} 367 368assert_equal 'ok', %q{ 369 m = Mutex.new 370 Thread.new { m.lock; sleep 2; m.unlock } 371 sleep 1; m.lock 372 :ok 373} 374 375assert_equal 'ok', %q{ 376 t = Thread.new {`echo`} 377 t.join 378 $? ? :ng : :ok 379}, '[ruby-dev:35414]' 380 381assert_equal 'ok', %q{ 382 begin 383 100.times{ 384 (1..100).map{ Thread.new(true) {|x| x == false } }.each{|th| th.join} 385 } 386 rescue NoMemoryError, StandardError 387 end 388 :ok 389} 390 391assert_equal 'ok', %{ 392 open("zzz.rb", "w") do |f| 393 f.puts <<-END 394 begin 395 m = Mutex.new 396 Thread.new { m.lock; sleep 1 } 397 sleep 0.3 398 parent = Thread.current 399 Thread.new do 400 sleep 0.3 401 begin 402 fork { GC.start } 403 rescue Exception 404 parent.raise $! 405 end 406 end 407 m.lock 408 pid, status = Process.wait2 409 $result = status.success? ? :ok : :ng 410 rescue NotImplementedError 411 $result = :ok 412 end 413 END 414 end 415 require "./zzz.rb" 416 $result 417} 418 419assert_finish 3, %q{ 420 require 'thread' 421 422 lock = Mutex.new 423 cond = ConditionVariable.new 424 t = Thread.new do 425 lock.synchronize do 426 cond.wait(lock) 427 end 428 end 429 430 begin 431 pid = fork do 432 # Child 433 STDOUT.write "This is the child process.\n" 434 STDOUT.write "Child process exiting.\n" 435 end 436 Process.waitpid(pid) 437 rescue NotImplementedError 438 end 439}, '[ruby-core:23572]' 440 441assert_equal 'ok', %q{ 442 begin 443 Process.waitpid2(fork {sleep 1})[1].success? ? 'ok' : 'ng' 444 rescue NotImplementedError 445 'ok' 446 end 447} 448 449assert_equal 'foo', %q{ 450 f = proc {|s| /#{ sleep 1; s }/o } 451 [ Thread.new { f.call("foo"); nil }, 452 Thread.new { sleep 0.5; f.call("bar"); nil }, 453 ].each {|t| t.join } 454 GC.start 455 f.call.source 456} 457