Posts mit dem Label Java werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Java werden angezeigt. Alle Posts anzeigen

Mittwoch, 26. August 2009

Nested Synchronize Blocks

In my new simulation project I have different threads accessing objects. The simulation server calculates periodically their states and the tournament server, handling all agents, is accessing them over distributed Ruby. Therefore I need to synchronize the sim objects. My first attempt looked something like this:
class SyncObject

  def initialize
    @semaphore = Mutex.new
  end

  def synchronize &block
    @semaphore.synchronize &block
  end

end
Before changing something in the sim objects, I synchronize them :
  object.synchronize do
    # change the state of the object
  end
But as things were growing, I suddently got some deadlocks. After some research I found out, that a thread was invoking synchronize on the same object multiple times. The semaphore object doesn't care which thread is locking it. As long it's locked it will block all threads until the block is finished. Even if it's the same thread, that locked the semaphore just before.
But I needed a different behaviour, I want to synchronize the objects from different threads. As far as I remember Java's synchronize behaves the same way.
Using rspec we could specify this behaviour with 2 tests:
it "should not block the same thread when synchronizing" do
    object = SyncObject.new
    object.synchronize do
      object.synchronize do
        object.synchronize do
          true.should be_true
        end
      end
    end
  end
it "should block two different threads when synchronizing" do
    object = SyncObject.new
    wait_for_me = true
    object.synchronize do
      Thread.fork do
        object.synchronize do
          wait_for_me = false
        end
      end
      sleep 1
      wait_for_me.should be_true
    end
    wait_for_me.should be_false
  end
The first test's pretty straight forward, we want to allow nested synchronize blocks for the same thread.
For the second test we need two different threads. The first thread locks the object and lunches a second thread. The first one returns immediately after fork, while the second one is launched in the meantime. So while the first is waiting for a second, the second thread is trying to achieve the lock and is blocked until the first one releases it on line 12. Only now the second thread gets access to the object and can set wait_for_me to false.
Of course both tests fail (or get some deadlocks) with the implemention above. The second version of synchronize looks now like this:
class SyncObject

  def initialize
    @semaphore = Mutex.new
  end

  def synchronize
    unless @current_thread == Thread.current
      @semaphore.synchronize do
        @current_thread = Thread.current
        yield
        @current_thread = nil
      end
    else
      yield
    end
  end

end
The first time synchronize is accessed, @current_thread is set to the current running thread. The semaphore is locked and the blocked yield. If in the meantime a different thread invokes synchronize, it will be blocked until the first one finishes the block. Else if the same thread access the method in the meantime, it will not try to lock the semaphore again, but can yield its new block immediately.

Sonntag, 5. April 2009

Reading Binary Files with Ruby

For my current project I need to read some binary data with Ruby. The data file is formatted as 16-bit BINARY INTEGERS, hi-byte-first order with 2160 x 4320 data values.

From my Java days I knew the DataInputStream class. With it it's every easy to read the data, just use io.readShort().
Therefore I was looking everywhere in IO and File for some methods to read the data in an appropriate format. But I couldn't find anything really useful as all methods are working with strings and characters.

But then I found the pack method in Array and its corresponding method unpack in String. With this two methods it's easy to read and write binary files in various formats.

Here the code snippet where I read the gzip compressed file. @size is in my case 4320 and @height an array of 2160. After reading the file I can access the data with @data[line][row].
Zlib::GzipReader.open(filename) do |gz|
  x = 0
  # read one line (16-Bit-Integer = 2 bytes)
  while line = gz.read(2 * @size) 
    @data[x] = line.unpack('s' * @size)
    x += 1
  end
end
If you need more, have a look at BitStruct. It provides a nice DSL for handling binaries.

Donnerstag, 28. Februar 2008

By reference oder doch by value?!

Bei der Vorbereitung einer Schulung für Ruby bin ich auf eine verwirrende Eigenschaft gestossen:

Objekte werden in Ruby immer by reference übergeben, da Variablen nichts anderes als Referenzen auf Objekte sind. Aber siehe da:

def inc(n)
   n = n + 1
end
i = 1
inc(i) # => 2
puts i # => 1


Sieht aber so aus als ob Ruby nicht per reference übergeben würde, sondern by value.
Doch ein Blick in Docu zeigt, dass die Methode '+' ein neues Objekt mit dem Wert 2 zurückgibt, auf das nun n zeigt. Während i immer noch auf das alte Objekt mit dem Wert 1 zeigt. Würde Ruby kein neues Objekt erzeugen, sondern den Methoden-Receiver tatsächlich ändern:

a = 1
b = 2
c = a + b


ja dann wäre nach dieser Operation nicht nur c = 3, sondern auch a = 3.

Das ist aber immer noch nicht die ganze Wahrheit. Auch im folgendem Beispiel scheint Ruby by value zu übergeben:

def swap x,y
   y, x = x, y
end

a = 1
b = 2
swap a, b
puts a       # => 1
puts b       # => 2


Auch hier zeigt x nach dem Aufruf zwar auf 2, aber a immer noch auf 1. Doch die eigentliche Frage ist, warum werden überhaupt zwei Referenzen gebildet?

Weil Ruby Referenzen by value übergibt!

Übrigens herrscht in der Java-Welt immer noch das Gerücht, dass primitive Types by value übergeben werden und Objekte by reference. Stattdessen verhält sich Java genau gleich.