如何让线程按照ID(使用信号量)的顺序开始工作?

时间:2018-03-02 15:48:59

标签: java multithreading semaphore pthread-barriers

我有10个线程,每个线程都有自己的ID,从1到10;所有线程都有2个阶段要做(即Phase1和phase2)。我试图让所有线程首先完成他们的Phase1,在任何线程进入phase2之前,使用信号量(我做了它并且它工作正常),但是然后我应该让所有10个线程按照他们的TID(线程ID)开始。 我尝试了很多方法,但没有得到结果!我得到的最终结果只适用于前4个线程(有时是5个或6个),然后其余线程出现顺序混乱!

这些是我创建的信号量:

...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;

这是我的线程方法:

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

turnTestAndSet方法如下:

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

    return false;
}

其中siTurn初始化为1。

我的代码(我认为)中的问题是,当一个线程到达While循环[while(!this.turnTestAndSet())]时,它可能会成功跳过循环(如果成功),但是另一个线程可能会在前一个线程进入第2阶段之前启动并执行其while循环!因此,在任何线程进入第2阶段之前,siTurn可能会保持递增。

我知道我应该以更好的方式使用信号量s2并尝试从中受益而不是将其用作互斥锁。 任何针对该技巧的新解决方案或修复我当前的解决方案?或使用信号量的一般解决方案,以便我可以将其应用于我的代码。

1 个答案:

答案 0 :(得分:0)

您可以使用条件变量来完成此操作。请参考我为Github项目编写的以下程序。在您的计划中使用相同的概念并解决您的问题。从下面的示例中,您可以了解如何控制线程的执行。

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;
}