Вы должны создать свой собственный планировщик задач, см. Как: создать планировщик задач, который ограничивает степень параллелизма
Редактировать: Для этого требуется больше кода, чем с семафором, но у меня есть ощущение, что это может работать лучше, потому что пул потоков, в котором выполняются задачи, не знает о вашем семафоре, а использование TaskScheduler воспроизводится их правила.
Редактировать 2: Одним из возможных недостатков использования семафора является то, что пул потоков может подумать, что ваша задача выполняет операции ввода-вывода и назначает их много за раз (чтобы они зависали и ждали, потому что им не нужен процессор). Используя TaskScheduler они будут запланированы точно тогда, когда есть место для них. Это определенно сохранит чистоту бассейна.