Fragment Description:



Synchonization study 5:
semaphores rendez-vous.
Having 2 concurrent processes, A(a1, a2) and B(b1, b2), each running 2 tasks, how to schedule the tasks in that order:
'a1 -> b1 -> a2 -> b2', with no timer? Organizing 'rendez-vous' of tasks is a fundamental problem of concurrency.
Apparently simple, it requires some well organized 'scheduling'.
Here is a solution, using Semaphores.
To be noted:
1- the number of semaphores used, 2.
2- the initial state of the semaphore is...
'0' that is unavailable, or locked, which will generate a wait for the task claiming it.
3- the thinking occurs when you define where the semaphores are to be involved and how they must be used (Acquire or Release).


rendezvousSemaphore

Go Playground

Last update, on 2015, Tue 17 Nov, 18:25:01

/* ... <== see fragment description ... */

package main

import (
    "fmt"
    "sync"
    // a robust semaphore implementation
    "github.com/robryk/semaphore"
)

var (
    s1 *semaphore.Semaphore
    s2 *semaphore.Semaphore
)

// Comment all the lines were 'sX.Acquire()' appear within Process A and B
// observe the difference
func processA(name string) {
    fmt.Printf("process1-TASK1: %s-%d\n", name, 1)

    s2.Acquire(1) // will block (wait) until s2 is released by processB
    s1.Release(1) // unblocks TASK1 in processB
    fmt.Printf("process1-TASK2: %s-%d\n", name, 2)
}
func processB(name string) {
    fmt.Printf("process2-TASK1: %s-%d\n", name, 1)

    s2.Release(1) //unblocks TASK2 in processA
    s1.Acquire(1) // will block (wait) until s1 is released by processA
    fmt.Printf("process2-TASK2: %s-%d\n", name, 2)
}

// Let's dispatch 2 concurrents processes
func dispatch(wg *sync.WaitGroup, f func(), g func()) {
    wg.Add(2)
    go func() {
        f()
        wg.Done()
    }()
    go func() {
        g()
        wg.Done()
    }()
}
func main() {
    wg := &sync.WaitGroup{}
    defer wg.Wait()
    // The 2 semaphores need to be increased (or eleased) to be available
    s1 = semaphore.New(0)
    s2 = semaphore.New(0)
    dispatch(wg, func() { processA("A") }, func() { processB("B") })
}

/* Expected Result
process1-TASK1: A-1
process2-TASK1: B-1
process1-TASK2: A-2
process2-TASK2: B-2
When lines s2.Acquire and s1.Acquire, we should get:
process1-TASK1: A-1
process1-TASK2: A-2
process2-TASK1: B-1
process2-TASK2: B-2
The Semaphores here allow to organize a Rendez-Vous scheduling
Try to generalize this rendez-vous to n tasks in m processes :)
*/



Comments