0

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.

Mikael
  • 171
  • 2
  • 12
  • Please change the language tag. This is not C++. – Pete Becker Mar 02 '18 at 16:10
  • Re, "...then I should make all the 10 threads start in order of their TID." That's a big red warning flag. Any time you think you want different threads to do things in a particular order, you should re-consider whether threads are the right way to solve your problem. The original problem that threads were invented to solve was how to write code for different activities that happen _indepedently_ of each other. That's still what threads do best. – Solomon Slow Mar 02 '18 at 17:56
  • Re, "I am trying to make all threads finish Phase1 first, before any thread [starts] phase2." Instead of having threads that each do two separate things, why not submit _tasks_ to a _thread pool_? First, submit ten "phase 1" tasks. Then, when those have all completed, you can submit ten "phase 2" tasks. – Solomon Slow Mar 02 '18 at 17:59

1 Answers1

0

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;
}
Abhijit Pritam Dutta
  • 5,521
  • 2
  • 11
  • 17