两个线程交替打印1~100
分析
两个线程要交替严格按照顺序打印数字1~100,那么两个线程之间必然进行通信,而线程之间进行通信的手段一般是条件变量。
其次,线程交替打印:1,2,3,…,100,那么一个线程打印奇数,一个打印偶数。
代码
#include <mutex>
#include <thread>
#include <iostream>
#include <functional>
#include <condition_variable>
#include <atomic>
std::mutex mtx_;
int count_ = 1;
const int maxNum_ = 100;
std::condition_variable cond_;
bool isOdd(const int num)
{
return (num%2 != 0);
}
bool isEven(const int num)
{
return !isOdd(num);
}
void print(int tid, std::function<bool(int)> calcFunc)
{
int num = 0;
do
{
{
std::unique_lock<std::mutex> lock(mtx_);
cond_.wait(lock, [&num, &calcFunc](){
num = count_;
return calcFunc(count_);
});
}
std::cout << "tid[" << tid << "]: " << num << "\n"; //
count_ += 1;
cond_.notify_one();
}while (num < maxNum_ - 1);
}
int main()
{
std::thread tid1(print, 1, isOdd);
std::thread tid2(print, 2, isEven);
tid1.join();
tid2.join();
return 0;
}
关键分析:
std::cout << "tid[" << tid << "]: " << num << "\n"; //
count_ += 1;
cond_.notify_one();
上述三行代码,顺序不能乱,一旦顺序乱了,就不能按照要求进行打印.
如果将第2行放到第一行,即先+1再打印, 刚执行完+1,操作系统虚假唤醒另一个线程,check条件满足,就往下执行了,造成乱序打印。
同理,如果将第一行放到第三行之后,先发出信号,另一个正被阻塞的线程收到信号以后,条件满足,执行后续的打印,与我们的打印造成乱序。
扩展: 多个线程进行交替打印
如果增加到三、四…多个线程来打印,本质还是不变,只需要增加每个线程的“条件“即可
如,五个线程交替打印:
#include <mutex>
#include <thread>
#include <iostream>
#include <functional>
#include <condition_variable>
#include <atomic>
std::mutex mtx_;
int count_ = 1;
const int maxNum_ = 100;
std::condition_variable cond_;
void print1(const int tid, std::function<bool(const int, const int)> calcFunc)
{
int num = 0;
do
{
{
std::unique_lock<std::mutex> lock(mtx_);
cond_.wait(lock, [&num, tid, &calcFunc](){
num = count_;
return calcFunc(num, tid);
});
}
std::cout << "tid[" << tid << "]: " << num << "\n"; //
count_ += 1;
cond_.notify_all();
}while (num < maxNum_ - 4);
}
bool isEqual(const int count, const int num)
{
return ((count-1) % 5) == num;
}
int main()
{
std::thread tid1(print1, 0, isEqual);
std::thread tid2(print1, 1, isEqual);
std::thread tid3(print1, 2, isEqual);
std::thread tid4(print1, 3, isEqual);
std::thread tid5(print1, 4, isEqual);
tid1.join();
tid2.join();
tid3.join();
tid4.join();
tid5.join();
return 0;
}