Как заставить потоки начинать свою работу в порядке их идентификаторов (используя семафоры)?

у меня 10 потоков и у каждого свой ID от 1 до 10; все потоки должны выполнять 2 фазы (т. е. фаза 1 и фаза 2). Я пытаюсь заставить все потоки сначала завершить свою фазу 1, прежде чем какой-либо поток войдет в фазу 2, используя семафоры (я сделал это, и это работает хорошо), но затем я должен запустить все 10 потоков в порядке их TID (идентификатор потока). Перепробовал много способов, но результата не получил! Конечный результат, который я получил, работает только для первых 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())], он может успешно пропустить цикл (в случае успеха), но другой поток может начать и выполнить свой цикл while до того, как предыдущий поток перейдет к фазе 2! Таким образом, siTurn может продолжать увеличиваться до того, как какой-либо поток войдет в фазу 2.

Я знаю, что должен лучше использовать семафор s2 и попытаться извлечь из него пользу, а не использовать его как мьютекс. Любое новое решение этого трюка или ремонт моего текущего решения ?? или общее решение с использованием семафоров, чтобы я мог применить его к своему коду.


person Mikael    schedule 02.03.2018    source источник
comment
Пожалуйста, измените тег языка. Это не С++.   -  person Pete Becker    schedule 02.03.2018
comment
Re, ... тогда я должен запустить все 10 потоков в порядке их TID. Это большой красный предупреждающий флаг. Каждый раз, когда вы думаете, что хотите, чтобы разные потоки выполняли действия в определенном порядке, вам следует пересмотреть вопрос о том, являются ли потоки правильным способом решения вашей проблемы. Первоначальная проблема, для решения которой были изобретены потоки, заключалась в том, как написать код для различных действий, происходящих независимо друг от друга. Это все еще то, что потоки делают лучше всего.   -  person Solomon Slow    schedule 02.03.2018
comment
Re, я пытаюсь заставить все потоки сначала завершить фазу 1, прежде чем любой поток [начнет] фазу 2. Вместо того, чтобы иметь потоки, каждый из которых выполняет две отдельные задачи, почему бы не отправить задачи в пул потоков? Сначала отправьте десять заданий этапа 1. Затем, когда все они будут выполнены, вы можете отправить десять задач фазы 2.   -  person Solomon Slow    schedule 02.03.2018


Ответы (1)


Вы можете сделать это, используя переменную условия. Пожалуйста, обратитесь к программе ниже, которую я написал для проекта 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;
}
person Abhijit Pritam Dutta    schedule 02.03.2018
comment
Можете ли вы поделиться версией вашего кода на github? Я спрашиваю об этом, потому что это поможет мне, если у вас есть связанная работа там. - person Jawad Adil; 29.03.2021
comment
Извините, Джавад, у меня нет версии github. - person Abhijit Pritam Dutta; 31.03.2021