如何让线程按照 ID 的顺序开始工作(使用信号量)?
How to I make threads starts their work in order of their IDs (using semaphores)?
我有10个线程,每个线程都有自己的ID,从1到10;所有线程都有 2 个阶段要做(即阶段 1 和阶段 2)。我试图让所有线程首先完成它们的阶段 1,在任何线程进入阶段 2 之前,使用信号量(我做到了并且效果很好),但是我应该让所有 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 循环!因此 siTurn 可能会在任何线程进入阶段 2 之前保持递增。
我知道我应该以更好的方式使用信号量 s2 并尝试从中受益,而不是将其用作互斥锁。
该技巧的任何新解决方案或我当前解决方案的修复?或使用信号量的通用解决方案,以便我可以将其应用到我的代码中。
您可以使用条件变量来做到这一点。请参考下面我为 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;
}
我有10个线程,每个线程都有自己的ID,从1到10;所有线程都有 2 个阶段要做(即阶段 1 和阶段 2)。我试图让所有线程首先完成它们的阶段 1,在任何线程进入阶段 2 之前,使用信号量(我做到了并且效果很好),但是我应该让所有 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 循环!因此 siTurn 可能会在任何线程进入阶段 2 之前保持递增。
我知道我应该以更好的方式使用信号量 s2 并尝试从中受益,而不是将其用作互斥锁。 该技巧的任何新解决方案或我当前解决方案的修复?或使用信号量的通用解决方案,以便我可以将其应用到我的代码中。
您可以使用条件变量来做到这一点。请参考下面我为 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;
}