

/* Thread_condition 是多线程的条件控制类，主要是控制线程的启停和退出
 * 线程创建后，一般是循环运行，
 * 为了防止线程暂满整个cpu，那么需要线程在不工作的是否进入等待状态。
 * Thread_condition 就可以控制线程的运行状态。
 *
	std::atomic<bool> m_pass_ever		//线程能否直接通过等待，对后面的线程也生效。
	std::atomic<bool> m_pass_once		//线程能否直接通过等待，一次（通过一次之后，wait里面自动改为false）
 * 外部调用notify系列的函数，唤醒等待的线程，让线程执行功能函数。
 * 如果需要线程循环多次执行功能函数，那么就使用 notify_all(true)，后面的线程可以直接通过等待了。
 * 再使用 notify_all(false) ，即可停止线程，让其继续等待。
 * 如果只想要线程执行一次，那就使用 notify_all(false, true)
 * 注：notify_all(false, true)和notify_one(false, true) 一样，只能让其中一个线程执行一次
 *
 * m_kill_flag //是否杀死线程，让线程强制退出，
 * 外部调用 kill_all() 函数，可以直接通知线程自动退出。
	//杀死所有的线程，强制退出线程函数，只是操作受当前Thread_condition影响的所有线程
	//唤醒所有线程，使其通过等待，但是不能运行功能函数，必须直接return
	// 注：只是修改m_kill为true，需要线程函数实时检测kill的状态，来return线程。
	//		通过等待之后，也要检查kill的状态，如果为真，那么就不能执行功能函数，应该直接return

 注：notify唤醒线程之后，wait里面的判断函数会重新判断。
 */

#ifndef LIDARMEASURE_THREAD_CONDITION_H
#define LIDARMEASURE_THREAD_CONDITION_H

#include <ratio>
#include <chrono>
#include <thread>
#include <atomic>
#include <mutex>
#include <condition_variable>


class Thread_condition
{
public:
	Thread_condition();
	Thread_condition(const Thread_condition& other) = delete;
	~Thread_condition();

	//无限等待，由 is_pass_wait 决定是否阻塞。
	//返回m_pass，
	bool wait();
	//等待一定的时间（默认时间单位：毫秒ms），由 is_pass_wait 决定是否阻塞。
	//return：is_pass_wait的结果，	true：线程直接通过等待，false：线程超时了，然后通过等待。
	//注意了：线程阻塞期间，是不会return的。
	bool wait_for_millisecond(unsigned int millisecond);

	//等待一定的时间（时间单位可调），由 is_pass_wait 决定是否阻塞。
	//return：is_pass_wait的结果，	true：线程直接通过等待，false：线程超时了，然后通过等待。
	//注意了：线程阻塞期间，是不会return的。
	template<typename _Rep, typename _Period>
	bool wait_for_ex(const std::chrono::duration<_Rep, _Period>& time_duration);

	//唤醒已经阻塞的线程，唤醒一个线程
	//pass_ever 或者 pass_once 为真时，才能唤醒线程。都为假时，线程进入等待。
	void notify_one(bool pass_ever, bool pass_once = false);
	//唤醒已经阻塞的线程，唤醒全部线程
	//pass_ever 或者 pass_once 为真时，才能唤醒线程。都为假时，线程进入等待。
	void notify_all(bool pass_ever, bool pass_once = false);
	//注：notify_all(false, true)和notify_one(false, true) 一样，只能让其中一个线程执行一次

	//杀死所有的线程，强制退出线程函数，只是操作受当前Thread_condition影响的所有线程
	//唤醒所有线程，使其通过等待，但是不能运行功能函数，必须直接return
	// 注：只是修改m_kill为true，需要线程函数实时检测kill的状态，来return线程。
	//		通过等待之后，也要检查kill的状态，如果为真，那么就不能执行功能函数，应该直接return
	void kill_all();

	//判断是否或者，return !m_kill_flag
	bool is_alive();

public:

	bool get_kill_flag();
	bool get_pass_ever();
	bool get_pass_once();
	void set_kill_flag(bool kill);
	void set_pass_ever(bool pass_ever);
	void set_pass_once(bool pass_once);
	void reset(bool kill = false, bool pass_ever = false, bool pass_once = false);

protected:
	//判断线程是否可以通过等待，wait系列函数的判断标志
	//注：m_kill或者m_pass为真时，return true
	static bool is_pass_wait(Thread_condition * other);

	std::atomic<bool> 		m_kill_flag;			//是否杀死线程，让线程强制退出，
	std::atomic<bool> 		m_pass_ever;			//线程能否直接通过等待，对后面的线程也生效。
	std::atomic<bool> 		m_pass_once;			//线程能否直接通过等待，一次（通过一次之后，wait里面自动改为false）

	std::mutex 				m_mutex;				//线程的锁
	std::condition_variable m_condition_variable;	//线程的条件变量

private:

};

//等待一定的时间（时间单位可调），由 is_pass_wait 决定是否阻塞。
//return：is_pass_wait的结果，	true：线程直接通过等待，false：线程超时了，然后通过等待。
//注意了：线程阻塞期间，是不会return的。
template<typename _Rep, typename _Period>
bool Thread_condition::wait_for_ex(const std::chrono::duration<_Rep, _Period>& time_duration)
{
	std::unique_lock<std::mutex> loc(m_mutex);
	m_condition_variable.wait_for(loc, std::chrono::duration<_Rep, _Period>(time_duration), std::bind(is_pass_wait, this));
	bool t_pass = is_pass_wait(this);
	m_pass_once = false;
	return t_pass;
}

#endif //LIDARMEASURE_THREAD_CONDITION_H
