Няма да говорим за паралелни алгоритми и други подобни неща
Ще говорим за конкурентност на по-практическо ниво
Системен примитив
child_id = fork()
if child_id
puts "This is the parent"
else
puts "This is the child speaking!"
end
Има и друга версия:
fork do
puts "This is the child"
end
puts "This is the parent"
Всъщност, повечето неща са в модул `Process`:
Process.fork
Process.wait
Process.waitall
Process.waitpid
Process.wait
чака някое от децата да приключи и връща pid-а му,
а $?
съдържа Process::Status
.
fork { exit 99 } # 30188
Process.wait # 30188
$?.exitstatus # 99
Process.wait2
е сходно, но връща масив от pid и Process::Status
:
fork { exit 99 } # 30197
Process.wait2 # [30197, #<Process::Status: pid 30197 exit 99>]
Process.waitpid(pid)
чака детето конкретно дете да приключи:
pid = fork do
sleep 1
puts "Child"
end
Process.waitpid(pid)
puts "Parent"
Process.waitall
чака всички деца да приключат
fork { sleep 1; puts "1" }
fork { sleep 2; puts "2" }
Process.waitall
puts "3"
Process.exec
заменя текущия процес с изпълнение на команда:
fork do
exec('ls')
puts "Unreachable code"
end
Process.daemon
"откача" процеса от терминала и го пуска в background.
fork do
Process.daemon
loop do
system "echo Spam >> ~/Desktop/spam"
sleep 1
end
end
Process.pid
връща process id на текущия процес
Process.ppid
връща parent process id
getpgid
, gid
, setpgid
, uid
и т.н.
spawn
е швейцарско ножче за пускане на процесиСъздаването на нишка в Ruby е лесно:
thread = Thread.new do
puts "This is run in the thread"
puts "The thread is started immediatelly"
end
puts "This is run in the main thread"
Процесът приключва, когато основната нишка приключи. Ако искате да изчакате
някоя от създадените нишки да приключи преди процеса да излезе, ползвайте
Thread#join
.
thread = Thread.new do
sleep 1
puts "Thread done"
end
thread.join
puts "Process done"
Thread#value
блокира докато нишката не приключи и връща последния
оценен израз
thread = Thread.new do
2 + 2
end
thread.value # 4
Ако една нишка предизвика изключение, то няма да убие интерпретатора. Вместо това,
ще се появи в нишката, извикваща #value
или #join
.
thread = Thread.new do
raise "Oh noes!"
end
thread.join # error: RuntimeError
Можете да промените последното с Thread.abort_on_exception
.
Thread.abort_on_exception = true
Thread.main
връща основната нишка
Thread.current
връща текущата нишка
Thread.list
връща всички нишкиThread#priority
и
Thread#priority=
Променливи дефинирани в блога на нишката са (очевидно) локални за нишката
thread = Thread.new { something = 1 }
thread.join
something # error: NameError
Блокът на нишката вижда променливите отвън.
answer = 1
thread = Thread.new { answer = 2 }
thread.join
answer # 2
Можете да подавате стойности на нишката през Thread.new
n = 10
thread = Thread.new(n) do |number|
n # 20
number # 10
end
n = 20
thread.join
Всяка нишка функционира като хеш от символи. Така може да правите thread-local променливи
Thread.current[:x] = 10
thread = Thread.new do
Thread.current[:x] # nil
Thread.current[:x] = 20
end
thread.join
Thread.current[:x] # 10
lock
и unlock
lock
: Ако mutex-а е отключен го заключва и продължава нататък
lock
: Ако mutex-а е заключен, приспива нишката докато се отключи, след това прави горното
unlock
: Отключва mutex-а
$mutex = Mutex.new
def stuff
# pre-lock
$mutex.lock
# critical
$mutex.unlock
# post-lock
end
t1 = Thread.new { loop { stuff } }
t2 = Thread.new { loop { stuff } }
t1.join
t2.join
$mutex = Mutex.new
def stuff
# pre-lock
$mutex.synchronize do
# critical
end
# post-lock
end
t1 = Thread.new { loop { stuff } }
t2 = Thread.new { loop { stuff } }
t1.join
t2.join