help on threads synchronization

Discussion in 'Ruby' started by Zd Yu, May 13, 2011.

  1. Zd Yu

    Zd Yu Guest

    How to make two threads do something in turn, i.e., A => B => A => B
    ....?

    I know the code below is not correct, but I do not know how to make it
    correct. Could anybody help?

    =======================================
    mutex=Mutex.new

    t=Thread.new {
    while true
    Thread.stop
    puts "B move..."
    Thread.main.wakeup
    end
    }

    while true
    puts "A move..."
    t.wakeup
    Thread.stop
    end

    --
    Posted via http://www.ruby-forum.com/.
     
    Zd Yu, May 13, 2011
    #1
    1. Advertising

  2. On Fri, May 13, 2011 at 9:33 AM, Zd Yu <> wrote:
    > How to make two threads do something in turn, i.e., A =3D> B =3D> A =3D> =

    B
    > ....?
    >
    > I know the code below is not correct, but I do not know how to make it
    > correct. Could anybody help?
    >
    > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=

    =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
    > mutex=3DMutex.new
    >
    > t=3DThread.new {
    > =A0while true
    > =A0 =A0Thread.stop
    > =A0 =A0puts "B move..."
    > =A0 =A0Thread.main.wakeup
    > =A0end
    > }
    >
    > while true
    > =A0puts "A move..."
    > =A0t.wakeup
    > =A0Thread.stop
    > end


    Since you want to have one thread active at a time only this is not a
    case for threads. If at all you might use Fibers:

    http://www.rubyinside.com/ruby-fibers-8-useful-reads-on-rubys-new-concurren=
    cy-feature-1769.html
    http://www.ruby-doc.org/core-1.9/classes/Fiber.html

    The simplest solution is to code interchanges directly:

    Actor =3D Struct.new :number do
    def alive?; rand(10) !=3D 0 end

    def step
    printf "Actor %p working...\n", number
    end
    end

    acts =3D Array.new(2) {|i| Actor.new i }

    until acts.empty?
    acts.delete_if do |a|
    a.step
    !a.alive?
    end
    end

    Kind regards

    robert

    --=20
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
     
    Robert Klemme, May 13, 2011
    #2
    1. Advertising

  3. Zd Yu

    jake kaiden Guest

    hi Zd -

    how about using a GLib::Timeout instead of threads? threads can gum
    up the works if you're not careful...

    ######
    require 'glib2'

    repeat = true

    GLib::Timeout.add(1000){
    p '=>A'
    true ? repeat : false
    }

    GLib::Timeout.add(1000){
    p '=>B'
    true ? repeat : false
    }
    ######

    the true or false at the end of each block tells the timeout whether
    to repeat the block or stop - true repeats, false stops. the argument
    to the #.add method is the amount of time to wait before repeating.


    - j

    --
    Posted via http://www.ruby-forum.com/.
     
    jake kaiden, May 13, 2011
    #3
  4. Zd Yu

    Zd Yu Guest

    Thanks Robert and Jake. I must use threads. Actually my original problem
    is much more complicated and I just simplified it to ask in this forum.

    I just found the ConditionVariable class, and it seems it is the key to
    implement such cooperation between threads.

    Please help review my code below. Let me know if I did anything wrong.

    (I have tested the code with both C Ruby and JRuby, and it works well.)
    =====================================
    require 'thread'

    mutex = Mutex.new
    resource = ConditionVariable.new
    next_one = 'A'

    a = Thread.new {
    while true
    mutex.synchronize {
    while next_one != 'A'
    resource.wait(mutex)
    end
    }
    puts "A..."
    next_one = 'B'
    mutex.synchronize {
    resource.signal
    }
    end
    }

    b = Thread.new {
    while true
    mutex.synchronize {
    while next_one != 'B'
    resource.wait(mutex)
    end
    }
    puts "B..."
    next_one = 'A'
    mutex.synchronize {
    resource.signal
    }
    end
    }

    a.join
    b.join
    exit

    --
    Posted via http://www.ruby-forum.com/.
     
    Zd Yu, May 13, 2011
    #4
  5. On Fri, May 13, 2011 at 2:48 PM, Zd Yu <> wrote:
    > Thanks Robert and Jake. I must use threads.


    Why?

    > Actually my original problem
    > is much more complicated and I just simplified it to ask in this forum.


    Then apparently you did not abstract the problem properly. Before we
    jump to solutions can you explain why you say you must use threads?
    What is the real problem you are trying to solve?

    > I just found the ConditionVariable class, and it seems it is the key to
    > implement such cooperation between threads.
    >
    > Please help review my code below. Let me know if I did anything wrong.


    The whole approach is too complicated for the problem to be solved (see above).

    Cheers

    robert

    --
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
     
    Robert Klemme, May 13, 2011
    #5
  6. Zd Yu

    Zd Yu Guest

    Robert,

    I want to use multi-threading + JRuby to achieve better performance.

    My problem has a single input file that contains millions of lines. Each
    line is the input of a time-consuming computing and will generate an
    output result.

    What in my mind is:

    1. the main thread prepares N working threads, and put them into sleep
    state.
    2. the main thread open the input file and pass the file object to each
    thread[:file]
    3. the main thread send a "GO" command to all the working threads
    4. each thread works in the below loop:
    4.1 lock the mutex associated with the file object, read a line, and
    then unlcok. if EOF is encountered, exit from the loop.
    4.2 do the very time-consuming computing
    4.3 put the result to thread.current[:result]
    4.4 signal the main thread to pick up the result
    4.5 go to sleep state (waiting for being waken up by the main thread)
    5. the main thread works in the below loop:
    5.1 go to sleep state until being waken up by one of the working
    threads.
    5.2 check all the working threads' [:result] and extract them out and
    do some aggregation.
    5.3 for those threads whose result has been picked, send a signal to
    let them proceed with the next line.
    6. once all the working threads finish, the main thread output the
    aggregated result.

    --
    Posted via http://www.ruby-forum.com/.
     
    Zd Yu, May 16, 2011
    #6
  7. On Mon, May 16, 2011 at 3:19 AM, Zd Yu <> wrote:
    > I want to use multi-threading + JRuby to achieve better performance.
    >
    > My problem has a single input file that contains millions of lines. Each
    > line is the input of a time-consuming computing and will generate an
    > output result.
    >
    > What in my mind is:
    >
    > 1. the main thread prepares N working threads, and put them into sleep
    > =A0 state.
    > 2. the main thread open the input file and pass the file object to each
    > =A0 thread[:file]
    > 3. the main thread send a "GO" command to all the working threads


    Did you ever hear of blocking queues?

    > 4. each thread works in the below loop:
    > =A0 4.1 lock the mutex associated with the file object, read a line, and
    > =A0 =A0 =A0 then unlcok. if EOF is encountered, exit from the loop.
    > =A0 4.2 do the very time-consuming computing
    > =A0 4.3 put the result to thread.current[:result]
    > =A0 4.4 signal the main thread to pick up the result
    > =A0 4.5 go to sleep state (waiting for being waken up by the main thread)
    > 5. the main thread works in the below loop:
    > =A0 5.1 go to sleep state until being waken up by one of the working
    > =A0 =A0 =A0 threads.
    > =A0 5.2 check all the working threads' [:result] and extract them out and
    > =A0 =A0 =A0 do some aggregation.
    > =A0 5.3 for those threads whose result has been picked, send a signal to
    > =A0 =A0 =A0 let them proceed with the next line.
    > 6. once all the working threads finish, the main thread output the
    > =A0 aggregated result.


    This sounds like a very typical application of farmer worker. You
    create two queues, one for tasks and one for results. Then you start
    a thread which fetches results from the result queue and processes
    them. Then you start a number of threads which read from the tasks
    queue, process tasks and place results in the result queue. Finally
    you use Thread#value to join on the result processor.

    # untested
    require 'thread'

    WORKERS =3D 5

    tasks =3D SizedQueue.new WORKERS * 10
    results =3D SizedQueue.new WORKERS * 10

    agg =3D Thread.new do
    state =3D Hash.new 0
    th =3D WORKERS

    while th > 0
    x =3D results.deq

    if Thread =3D=3D=3D x
    th -=3D 1
    else
    # aggregate
    state[x] +=3D 1
    end
    end

    state
    end

    workers =3D WORKERS.times.map do
    Thread.new do
    until (it =3D tasks.deq) =3D=3D tasks
    results.enq(process it)
    end
    results.enq(Thread.current)
    end
    end

    p agg.value

    Kind regards

    robert

    --=20
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
     
    Robert Klemme, May 16, 2011
    #7
  8. Zd Yu

    Zd Yu Guest

    Thank you Robert!

    I did not know the Queue/SizedQueue classes. They perfectly meet my
    requirements.

    Thank you again!

    --
    Posted via http://www.ruby-forum.com/.
     
    Zd Yu, May 16, 2011
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. yoda
    Replies:
    2
    Views:
    476
    =?utf-8?Q?Bj=C3=B6rn_Lindstr=C3=B6m?=
    Aug 1, 2005
  2. Replies:
    7
    Views:
    410
  3. Replies:
    4
    Views:
    386
    Daniel Pitts
    Feb 8, 2008
  4. Replies:
    21
    Views:
    750
    Lasse Reichstein Nielsen
    Jun 27, 2008
  5. Replies:
    5
    Views:
    123
Loading...

Share This Page