All pastes #37830 Raw Edit

Sergei

public ruby v1 · immutable
#37830 ·published 2006-01-21 16:19 UTC
rendered paste body
#!/usr/bin/ruby# The Santa Claus problem# wzieto w Allen B. Downey "The Little Book of Semaphores" ## Santa Claus spi w swojej pracowni na Polnocnym Biegunie i # moze zostac obudzony tylko jezeli:#   (1) Wsystkie 9 reniferow wroca z wakacji#   (2) Elfy maja problemy z produkowaniem zabawek# Zeby pozwolic Sant'ie sie wyspac elfy moga obudzic# go tylko jezeli trzy elfa maja problemy. Kiedy# Santa rozwiaze problemy tych 3 elfow i jezeli jacys# inny elfy maja problemy, to musza poczekac az tamci# 3 wroca. Co wiecej jezeli Santa budzac sie zobaczy# jednoczesnie 9 reniferow oraz 3 elfy, to zajmuje sie# reniferami, bo wazne jest dostarczyc prezenty na czas# (renifery maja zwyczaj wracac w ostatniej chwili).# Wracajace renifery czekaja az uzbiera sie ich 9# i tylko pozniej zostaja umieszczone w sanie. Zakladamy# ze jest dowolna ilosc elfow ale tylko 9 reniferow# Semafor licznikowy zaimplementowany uzywajac wait i signal# zrodlo: http://www.imasy.or.jp/~fukumoto/ruby/semaphore.rbclass CountingSemaphore    def initialize(initvalue = 0)        @counter = initvalue        @waiting_list = []    end    def wait        Thread.critical = true        if (@counter -= 1) < 0            @waiting_list.push(Thread.current)            Thread.stop        end        self    ensure        Thread.critical = false    end    def signal        Thread.critical = true        begin            if (@counter += 1) <= 0                t = @waiting_list.shift                t.wakeup if t        end        rescue ThreadError            retry        end        self    ensure        Thread.critical = false    end    alias down wait    alias up signal    alias P wait    alias V signal    def exclusive        wait        yield    ensure        signal    end    alias synchronize exclusiveendSemaphore = CountingSemaphoreelves = 0 # licznik elfowreindeer = 0 # licznik reniferowsanta_sem = Semaphore.new # Santa czeka az 9 reniferow go zasygnalizuje# zmienne globalne musza sie zaczynac od $, inaczej nie sa widoczne w funkcjach# reszta zmiennych nie jest globalna, ale uzywa sie tylko w blokach (do..end, for..end i podobnych)$reindeer_sem = Semaphore.new # renifery czekaja az Santa kaze im isc do sani   elf_tex = Semaphore.new(1) # elfy uzywaja tego semaforu zeby nie pozwolic wejsc wiecej niz 3 elfom$help_sem = Semaphore.new # elfy jak dostaja pomocy blokuja sie tutaj, Santa jak im pomoze puszcza ichrequire 'thread'mutex = Mutex.new # chroni dostep do elves i reindeer# renifer jedzie na wakacje # sleep pobiera czas w sekundach ale jako float# rand zwraca wartos 0..1, wiec wakacje trwaja od 0 do 2 sekunddef reindeer_vacation    sleep(2.0*rand)end# elf spia i nie potrzebuja pomocydef elf_sleep    sleep(2.0*rand)end# Santa wstaje i przygotowuje sanie, puszczajac wszystkich reniferow# renifery jada i rozdaja prezenty (po tej funkcji zakladamy ze juz rozdali)def prepare_sleigh    sleep(2.0*rand)    for i in 1..9        $reindeer_sem.signal    endend# renifery czekaja az Santa ich umiesci w saniedef get_hitched    $reindeer_sem.waitend# Santa pomaga trzem elfom i puszcza ichdef help_elves    sleep(2.0*rand)    $help_sem.signal    $help_sem.signal    $help_sem.signalend# Elfy czekaja az Santa im pomozedef get_help    $help_sem.waitend# Watek Santysanta_thread = Thread.new do    while true        puts "Santa spi"        santa_sem.wait        puts "Ktos obudzil Sante"        mutex.synchronize do            if reindeer == 9                puts "Jest 9 reniferow Santa idzie ich umiescic w sanie"                reindeer = 0                prepare_sleigh                puts "Santa umiescil 9 reniferow w sanie"            elsif elves == 3                puts "Santa idzie pomoc 3 elfom z zabawkami"                help_elves                puts "Santa skonczyl pomagac elfom z zabawkami"            end        end    endend# Watki reniferowreindeer_threads = []for i in 1..9    reindeer_threads << Thread.new(i) do |nr|         while true            puts "renifer #{nr} jedzie na wakacje"            reindeer_vacation            puts "renifer #{nr} przyjechal z wakacje i czeka az Santa go umiesci w sanie"            mutex.synchronize do                reindeer += 1                if reindeer == 9                    santa_sem.signal                end            end            get_hitched        end    endend# Watki elfownelves = 3elves_threads = []for i in 1..nelves    elves_threads << Thread.new(i) do |nr|        while true            puts "elf #{nr} chce pomocy z zabawkami"            elf_tex.wait            mutex.synchronize do                elves += 1                if elves == 3                    puts "jest trzech elfow budzimy Sante"                    santa_sem.signal                else                    elf_tex.signal                end            end            get_help            mutex.synchronize do                elves -= 1                if elves == 0                    elf_tex.signal                end            end            elf_sleep        end    endend # W Ruby jesli glowny watek nie ma nic do roboty to nie czeka na inne # watki i umiera, wiec musimy czekac az sie skonczy watek Santy # (a nie skonczy sie nigdy), wiec program tez sie nigdy nie skonczy# chyba ze wcisniemy Ctrl-Csanta_thread.join