class binary_semaphore
{ public: /**Wait until semaphore becomes signalled, and atomically reset the state
to non-signalled*/ void wait(); /** signals the semaphore */ void wake();
/* Re-read current value after acquiring the lock*/ if (num <= value() &&
(!thread_local_waiter.m_group_commit_leader || m_lock))
{
lk.unlock();
do_completion_callback(callback); return lock_return_code::EXPIRED;
}
if (!m_lock)
{ /* Take the lock, become group commit leader.*/
m_lock = true; #ifndef DBUG_OFF
m_owner_id = std::this_thread::get_id(); #endif if (callback)
m_pending_callbacks.push_back({num,*callback}); return lock_return_code::ACQUIRED;
}
if (callback && (m_waiters_list || num <= pending()))
{ /* Ifnum>pending(),wehaveagoodcandidateforthenextgroup commitlead,thatwillbetakingoverthelockaftercurrentowner releasesit.Weputcurrentthreadintowaiter'slistsoitsleeps andcanbesignaledandmarkedasgroupcommitleadduringlockrelease.
/* Update current value. */
ut_a(num >= value());
m_value.store(num, std::memory_order_relaxed);
/* Wakewaitersforvalue<=currentvalue. Wakeonemorewaiter,whowillbecomethegroupcommitlead.
*/
group_commit_waiter_t* cur, * prev, * next;
group_commit_waiter_t* wakeup_list = nullptr; for (auto& c : m_pending_callbacks)
{ if (c.first <= num)
{ if (callback_count < array_elements(callbacks))
callbacks[callback_count++] = c.second; else
c.second.m_callback(c.second.m_param);
}
}
for (prev= nullptr, cur= m_waiters_list; cur; cur= next)
{
next= cur->m_next; if (cur->m_value <= num)
{ /* Move current waiter to wakeup_list*/
if (!prev)
{ /* Remove from the start of the list.*/
m_waiters_list = next;
} else
{ /* Remove from the middle of the list.*/
prev->m_next= cur->m_next;
}
/* Append entry to the wakeup list.*/
cur->m_next = wakeup_list;
wakeup_list = cur;
} else
{
prev= cur;
}
}
if (m_pending_callbacks.size() || m_waiters_list)
{ /* Ensurethatafterthisthreadreleasedthelock, thereisanewgroupcommitleader Wetakethisfromwaiterslistorwakeuplist.It mightlooklikeaspuriouswake,butinfactwejust ensurethewaiterdonotwaitforeternity.
*/ if (m_waiters_list)
{ /* Move one waiter to wakeup list */ auto e= m_waiters_list;
m_waiters_list= m_waiters_list->m_next;
e->m_next= wakeup_list;
e->m_group_commit_leader= true;
wakeup_list = e;
} elseif (wakeup_list)
{
wakeup_list->m_group_commit_leader=true;
} else
{ /* Tell the caller that some pending callbacks left, and he should
do something to prevent stalls. This should be a rare situation.*/
ret= m_pending_callbacks[0].first;
}
}
lk.unlock();
/* Releasedesignatednextgroupcommitleadfirst, tominimizespuriouswakeups.
*/ if (wakeup_list && wakeup_list->m_group_commit_leader)
{
next = wakeup_list->m_next;
wakeup_list->m_sema.wake();
wakeup_list= next;
}
for (size_t i = 0; i < callback_count; i++)
callbacks[i].m_callback(callbacks[i].m_param);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.