std::condition_variable bug
wait_until受系统时间修改导致等待不准确 (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) )
代码中使用了std::condition_variable 来实现信号量,但是当修改了系统时间后会导致信号量提前(往后改系统时间)延后触发(往前改系统时间),究其原因是信号量的wait_for 或 wait_until接口以系统时钟作为标准导致。**
实例测试代码
采用usleep std::sleep_for boost::condition_variable std::condition_variable 作比较 ,程序启动后往后前调整几秒钟时间。
#include"toolkit/std_threadpool.hpp" //线程池
#include <iostream>
#include<functional>
#include <thread>
#include "toolkit/elapsed_timer.hpp" //计时器
#include "toolkit/semaphore.hpp" //信号量
#include <boost/interprocess/sync/interprocess_semaphore.hpp>//boost信号量
#include <boost/date_time.hpp>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using std::cout;
using std::endl;
#include<unistd.h>
void do_usleep(int ms)
{
AS120::elapsed_timer time;
cout << __FUNCTION__ << " "<< ms << " MS start!"<<endl;
usleep(ms*1000);
cout << __FUNCTION__ << " "<< ms << " MS over! "<< time.elasped()<<endl;
}
void do_std_sleep_for(int ms)
{
AS120::elapsed_timer time;
cout << __FUNCTION__ << " "<< ms << " MS start!"<<endl;
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
cout << __FUNCTION__ << " "<< ms << " MS over!"<< time.elasped()<<endl;
}
void do_boost_cv_wait(int ms)
{
cout << __FUNCTION__ << " "<< ms << " MS start!"<<endl;
AS120::elapsed_timer time;
boost::mutex mtx;
boost::condition_variable cv;
boost::unique_lock<boost::mutex> lk(mtx);
auto finished = cv.wait_until(lk, boost::chrono::steady_clock::now() +
boost::chrono::milliseconds(ms), [&] {
return false;
});
cout << __FUNCTION__ << " "<< ms << " MS over!"<< time.elasped()<<endl;
}
void do_std_cv_wait(int ms)
{
cout << __FUNCTION__ << " "<< ms << " MS start!"<<endl;
AS120::elapsed_timer time;
std::mutex mtx;
std::condition_variable cv;
std::unique_lock<std::mutex> lk(mtx);
auto finished = cv.wait_until(lk, std::chrono::steady_clock::now() +
std::chrono::milliseconds(ms), [&] {
return false;
});
cout << __FUNCTION__ << " "<< ms << " MS over!"<< time.elasped()<<endl;
}
void do_semaphore_wait(int ms)
{
cout << __FUNCTION__ << " "<< ms << " MS start!"<<endl;
AS120::elapsed_timer time;
AS120::semaphore sem;
sem.timed_wait_ms(ms);
cout << __FUNCTION__ << " "<< ms << " MS over!"<< time.elasped()<<endl;
}
int main(int argc,char** argv)
{
AS120::std_threadpool pl(10);
int TIME_MS = 20000;
if (argc > 1)
{
TIME_MS = std::stoi(argv[1]);
}
cout <<"TIME_MS is " << TIME_MS << endl;
pl.schedule([](int ms){
do_usleep(ms);
},TIME_MS);
pl.schedule([](int ms){
do_std_sleep_for(ms);
},TIME_MS);
pl.schedule([](int ms){
do_boost_cv_wait(ms);
},TIME_MS);
pl.schedule([](int ms){
do_std_cv_wait(ms);
},TIME_MS);
getchar();
}
输出
TIME_MS is 20000
do_usleep 20000 MS start!
do_std_sleep_for 20000 MS start!
do_boost_cv_wait 20000 MS start!
do_std_cv_wait 20000 MS start!
do_boost_cv_wait 20000 MS over!20000
do_std_sleep_for 20000 MS over!20000
do_usleep 20000 MS over! 20000
do_std_cv_wait 20000 MS over!25660
说明标准库的条件变量等待的时间不准一点都不steady
项目中替换为boost::condition_variable
替换为boost库后 信号量实现的头文件更换为了
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/chrono.hpp>
由于信号量为hpp头文件库 且项目中大量使用的是标准库,估计头文件污染导致程序crash(heap-buffer-overflow ,双析构)奇怪的情况。
必须重写信号量 将定义h和实现cpp分离开 防止boost的头文件污染到标准库中。
目前可行。