ruby: așteptând un fir pentru a elibera o resursă

Eu folosesc rubinul 1.9.3. Am un fir de lungă durată care preia locurile de muncă dintr-o coadă. Firele utilizează un mutex pentru a proteja o secțiune critică în care firul face procesarea pentru lucrare. Să presupunem că datele de lucru conțin câmpul item_id .

Fișierul principal primește detalii despre o lucrare dintr-o sursă externă, inclusiv item_id , și anulează lucrările în coadă. Este posibil ca firul principal să primească același cod item_id de mai multe ori în diferite lucrări.

Firul principal are, de asemenea, acces la mutex-ul firului și la item_id pentru lucrarea curentă.

Obiectivul meu este de a împiedica firul principal să introducă o lucrare a cărei cod item_id se află pe coadă sau este procesat de fir. Dacă se întâmplă această situație, firul principal trebuie blocat până când item_id este procesat. Firul principal ar trebui să blocheze numai în această situație sau când așteaptă lucrări externe. Vreau, de asemenea, să evit ocupat în așteptare.

Am încercat deja să folosesc un ConditionVariable , dar acest lucru nu funcționează deoarece firul principal poate apela wait după /code> la încheierea procesării. Acest lucru provoacă un blocaj, deoarece signal nu este apelat din nou la ConditionVariable din nou.

EDIT: Voi simplifica problema. În prezent, îmi pasă doar dacă item_idul primit este tratat în prezent de firul respectiv. Dacă este în coadă, dar nu a fost încă dequeued, nu-mi pasă de duplicat.

Iată un eșantion minim:

require 'thread'

class WorkerThread < Thread
  attr_reader :item_id
  def initialize(queue)
    @queue = queue
    @item_id = nil
    super(&method(:main))
  end
  private
  def main
    loop do
      begin
        @item_id = @queue.deq
        print "[t] working on #{item_id}\n"
        sleep 1
        print "[t] done with #{item_id}\n"
      ensure
        @item_id = nil
      end
    end
  end
end

queue = SizedQueue.new(1)
thread = WorkerThread.new(queue)

produced_ids = (1..10).map{ rand(1..3) }
# simulate item_ids from external source. In reality, we'd continue receiving these indefinitely.
print "[main] item_ids: #{produced_ids.inspect}\n"
produced_ids.each do |item_id|
  # yes, i know this is a race cond
  # I'm mainly interested in how to avoid this busy-wait.
  while thread.item_id == item_id
    print "[main] waiting for id #{item_id} to finish\n"
    sleep 0.5
  end
  queue.enq(item_id)
  print "[main] enqueued #{item_id} ---\n"
end

# possible race cond - but this is only for testing anyway
until queue.empty? and thread.item_id == nil
  sleep 0.5
end

Vă rugăm să nu-mi spuneți că am o condiție de cursă dacă am adăugat deja un comentariu despre el în cod.

0
@ code added Codul.
adăugat autor Kelvin, sursa
Cod poștal vă rog ...
adăugat autor maerics, sursa