On Sat, Aug 03, 2019 at 06:11:58PM +0900, 김규래 wrote: > I'm currently having trouble implementing the thread sleeping mechanism when > the queue is out of tasks. > Problem is, it's hard to maintain consistency between the thread sleeping > routine and the queues. > See the pseudocode below, > > 1. check queue is empty > 2. go to sleep > > if we go lock-free, the consistency between 1 and 2 cannot be maintained.
I thought we don't want to go lock-free, the queue operations aren't easily implementable lock-free, but instead with a lock for each of the queues, so in the multi-queue setting having locks on the implicit tasks that hold those queues. What can and should be done without lock is perhaps some preliminary check if a queue is empty, that can be done through __atomic_load. And, generally go to sleep is done outside of the critical section, inside of the critical section we decide if we go to sleep or not, and then go to sleep either (on Linux) using futexes, or otherwise using semaphores, both have the properties that one can already post to them before some other thread sleeps on it, and in that case the other thread doesn't actually go to sleep. The wake up (post on the semaphore or updating the memory + later futex wake) is sometimes done inside of a critical section, the updating of memory if it is not atomic increase/decrease and the latter depending on whether we remember from the atomic operation whether the wake up is needed or not and defer it until after the critical section. Given say: ++team->task_count; ++team->task_queued_count; gomp_team_barrier_set_task_pending (&team->barrier); do_wake = team->task_running_count + !parent->in_tied_task < team->nthreads; gomp_mutex_unlock (&team->task_lock); if (do_wake) gomp_team_barrier_wake (&team->barrier, 1); you can see the wake up is done outside of the critical section. If team->task_lock isn't used, there will be of course problems, say team->task_count and team->task_queued_count need to be bumped atomically, ditto operations on team->barrier, and the question is what to do with the team->task_running_count check, if that one is updated atomically too, maybe __atomic_load might be good enough, though perhaps worst case it might mean we don't in some cases wake anybody, so there will be threads idling instead of doing useful work, but at least one thread probably should handle it later. Jakub