Мьютекс вероятно берется на 10ки инструкций, в духе достань эту ноду из интрузив листа, почему задачи спят на мьютексе, любая разумная реализация мьютекса и pthread в том числе будет сначала крутится. Понятно что может не везти из-за планировщика оси, но кажется маловероятным при размере тредпула ~ количество ядер * ht
Зачем ждать задачи, если таска хочет их дождаться, почему не заниматься чем то полезным, например их исполнением?
Колбек как раз решает эту проблему, задача будет запущена, когда будут исполнены все необходимые для нее задачи. При этом ожидание будет в другом месте, там где вы ждёте итоговый результат, и это вероятно должен быть не тредпул.
Это можно решать через явные граф задач, но неясно зачем