I have a program with multiple threads, and I would like to have them all perform an asynchronous I/O action at given clock intervals (mostly to throttle them). I want the clock to be as accurate as I can make it, but assume I'm OK with the obvious constraints of trying to have an accurate clock in software. I don't think I want to put all the I/O objects in the busy-wait thread (and thus achieve inherent synchronization), because imagine there are so many of them that it substantially degrades the clock calculation. Assume each I/O operation individually is capable of keeping up with my clock period.
I'm wondering if I can use a condition_variable in a single busy loop to give me the highest possible precision timing, and then "tick" via a notify_all(). Here's conceptually what I would do:
Class
class clocker
{
public:
// Methods which spawn the threads, etc...
private:
std::atomic<std::chrono::high_resolution_clock::rep> m_clockPeriod_ns;
std::atomic<size_t> m_elapsedTicks;
std::condition_variable m_tick;
std::mutex m_tickMutex;
};
Clock Thread:
while (true)
{
auto end = std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::duration elapsed_ns;
// busy look timer for highest possible precision.
auto start = end;
while (elapsed_ns.count() < m_clockPeriod_ns)
{
end = std::chrono::high_resolution_clock::now();
elapsed_ns = end - start;
}
// it's possible the elapsed time is long relative to the clock period IF the high res clock
// doesn't actually have enough resolution. To get around this, figure out how many 'ticks'
// should have occurred.
m_elapsedTicks.store(elapsed_ns.count() / m_clockPeriod_ns);
m_tick.notify_all();
}
I/O Thread:
while (true)
{
std::unique_lock<std::mutex> lock(m_tickMutex);
m_tick.wait(lock);
for (int i = 0; i < m_elapsedTicks.load(); ++i)
{
// Do I/O operation
}
}
I see some issues with this approach, but I'm not totally sure how important they really are, or how necessarily to get around them:
- The documentation mentions that implementations may have spurious wakeups. This could be a problem, but is it really? Do common implementations (gcc, msvc) have spurious wakeups? In practice, how spurious are they? I think I can live with the occasional spur, but it would be a problem if the spur-to-notify ratio was > 1 certainly.
- Are there other glaring issues that I'm not seeing?
Aucun commentaire:
Enregistrer un commentaire