Skip to content

use it in qt #318

Description

@bizehao

This is the scheduling I implemented in QT, but it has issues and sometimes it won't be scheduled. Occasionally, I am confused and can't find where the problem lies

using namespace std::chrono_literals;
namespace {
	uint64_t milliseconds_until(
		const std::chrono::steady_clock::time_point& abs_time)
	{
		using std::chrono::duration_cast;
		auto now = std::chrono::steady_clock::now();
		if (now >= abs_time) return 0;
		return duration_cast<std::chrono::milliseconds>(abs_time - now).count() + 1;
	}
	bool is_max_time(const std::chrono::steady_clock::time_point& abs_time)
	{
		return abs_time == std::chrono::steady_clock::time_point::max();
	}
}

class scheduler : public boost::fibers::algo::algorithm
{
public:
	scheduler() {
		QTimer::singleShot(0, [this]() mutable {
			QEventLoop eventLoop;
			while (true) {
				if (has_ready_fibers()) {
					//eventLoop.processEvents(QEventLoop::ApplicationExec | QEventLoop::EventLoopExec);
					while (eventLoop.processEvents(QEventLoop::AllEvents));
					std::unique_lock< boost::fibers::mutex > lk(mtx_);
					cnd_.wait(lk);
				}
				else {
					eventLoop.processEvents(QEventLoop::WaitForMoreEvents);
				}
			}
			});
	};

	~scheduler() override {};

	void awakened(boost::fibers::context* ctx) noexcept override {
		BOOST_ASSERT(nullptr != ctx);
		BOOST_ASSERT(!ctx->ready_is_linked());
		ctx->ready_link(rqueue_); /*< fiber, enqueue on ready queue >*/
		if (!ctx->is_context(boost::fibers::type::dispatcher_context)) {
			++counter_;
		}
	}

	boost::fibers::context* pick_next() noexcept override {
		boost::fibers::context* ctx = nullptr;
		if (!rqueue_.empty()) {
			ctx = &rqueue_.front();
			rqueue_.pop_front();
			BOOST_ASSERT(nullptr != ctx);
			BOOST_ASSERT(boost::fibers::context::active() != ctx);
			if (!ctx->is_context(boost::fibers::type::dispatcher_context)) {
				--counter_;
			}
		}
		return ctx;
	}

	bool has_ready_fibers() const noexcept override {
		return 0 < counter_;
	}

	void suspend_until(std::chrono::steady_clock::time_point const& abs_time) noexcept override {
		if (!is_max_time(abs_time)) {
			QTimer::singleShot(milliseconds_until(abs_time), []() {
				boost::this_fiber::yield();
				});
		}
		cnd_.notify_one();
	}

	void notify() noexcept override {
		QTimer::singleShot(0, []() {
			boost::this_fiber::yield();
			});
	}

	// Non-copyable and non-movable
	scheduler(const scheduler&) = delete;
	scheduler& operator=(const scheduler&) = delete;
	scheduler(scheduler&&) = delete;
	scheduler& operator=(scheduler&&) = delete;

private:
	boost::fibers::mutex                            mtx_;
	boost::fibers::condition_variable               cnd_;
	std::size_t                                     counter_{ 0 };
	boost::fibers::scheduler::ready_queue_type      rqueue_;
};

//test code
boost::fibers::use_scheduling_algorithm<scheduler>();

boost::fibers::fiber ff{ []() {
		for (int i = 0; i < 10; i++) {
			boost::this_fiber::sleep_for(5s);
			qDebug() << "i: " << i;
		}
		} };

ff.detach();

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions