javamultithreadingsemaphorepthread-barriers

How to I make threads starts their work in order of their IDs (using semaphores)?


I have 10 threads and each has its own ID from 1 to 10; all threads have 2 Phases to do (i.e. Phase1 and phase2). I am trying to make all threads finish their Phase1 first, before any thread enter phase2, using semaphores (I did it and it works good), but then I should make all the 10 threads start in order of their TID (Thread ID). I tried many ways, but did not get a result! The final result I got is working only for the first 4 threads (sometimes 5 or 6) and then a mess in the order appears for the rest of threads!

These are my semaphores created:

...private static Semaphore mutex = new Semaphore(1);

 // s1 is to make sure phase I for all is done before any phase II begins
private static Semaphore s1 = new Semaphore(0);

// s2 is for use in conjunction with Thread.turnTestAndSet() for phase II proceed in the thread creation order
private static Semaphore s2 = new Semaphore(1);

private static int n=10;
private static int count = 0;

This is my method for the threads:

static class AcquireBlock extends BaseThread
{
    public void run()
    {
        mutex.P();

        phase1();
        count++;

        mutex.V();

        if (count == n)
        {
            s1.V();
        }

        s1.P();
        s1.V(); 

        while(!this.turnTestAndSet());

        s2.P();
        phase2();
        s2.V();
    }
} // class AcquireBlock

the turnTestAndSet method is as follows:

public synchronized boolean turnTestAndSet()
{
    if(siTurn == this.iTID)
    {
        siTurn++;
        return true;
    }

    return false;
}

where siTurn is initialized to 1.

The problem that I have in my code (I think), is that when a thread reaches the While loop [while(!this.turnTestAndSet())], it may successfully skip the loop (in case of success), but another thread might start and execute its while loop before the previous thread proceed to phase 2! So as the siTurn might keep incremented before any thread enter phase 2.

I know I should use semaphore s2 in a better way and try to benefit from it instead of using it as mutex. Any new solution to that trick or a repair for my current solution ?? or a general solution using semaphores so that I can applied it on my code.


Solution

  • You can do so by using condition variable. Please refer below program which I wrote for a Github project. Use the same concept in your program and fix your issue. From below example you can understand how you can control execution of threads.

    std::condition_variable _tcond1;
    std::condition_variable _tcond2;
    std::condition_variable _tcond3;
    
    class SimpleThread1
    {
    private:
        std::mutex  _lockprint;
        bool isThreadAlive = true;
        int iam;
        bool print = true;
    public:
        SimpleThread1(int iam)
        {
            while (print)
            {
                this->iam = iam;
                print = false;
            }
    
        }
        SimpleThread1(SimpleThread1 &st){};
    
        void PrintThread()
        {
            std::unique_lock<std::mutex> locker(_lockprint);
            _tcond1.wait(locker);
            //while (print)
            //{
                std::cout << "I am thread :" << iam << std::endl;
                //print = false;
            //}
    
            _tcond3.notify_one();
        }
        void operator()()
        {
            while (isThreadAlive)
             PrintThread();
        }
    
        void stopeThread()
        {
            isThreadAlive = false;
        }
    };
    
    class SimpleThread2
    {
    private:
        std::mutex  _lockprint;
        bool isThreadAlive = true;
    
    public:
        SimpleThread2(){}
        SimpleThread2(SimpleThread2 &st) {};
    
        void PrintThread()
        {
            std::unique_lock<std::mutex> locker(_lockprint);
            _tcond2.wait(locker);
            std::cout << "I am thread :2"<< std::endl;
            _tcond1.notify_one();
        }
        void operator()()
        {
            while (isThreadAlive)
                PrintThread();
        }
    
        void stopeThread()
        {
            isThreadAlive = false;
        }
    };
    
    
    class SimpleThread3
    {
    private:
        std::mutex  _lockprint;
        bool isThreadAlive = true;
    
    public:
        SimpleThread3(){}
        SimpleThread3(SimpleThread3 &st) {};
    
        void PrintThread()
        {
            std::unique_lock<std::mutex> locker(_lockprint);
            _tcond3.wait(locker);
            std::cout << "I am thread :3"<< std::endl;
            _tcond2.notify_one();
        }
        void operator()()
        {
            while (isThreadAlive)
                PrintThread();
        }
    
        void stopeThread()
        {
            isThreadAlive = false;
        }
    };
    
    int main()
    {
        SimpleThread1 st1(1);
        SimpleThread2 st2;
        SimpleThread3 st3;
        std::thread t1(st1);
        std::thread t2(st2);
        std::thread t3(st3);
        _tcond1.notify_one();
        t1.detach();
        t2.detach();
        t3.detach();
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
        st1.stopeThread();
        st2.stopeThread();
        st3.stopeThread();
        return 0;
    }