Вы можете сделать что-то вроде этого: с каждым заданием связана «очередь». Например:
Скажем, у вас есть 2 очереди. Ваша работа может сказать:
job[0].queue = 1; /* That job is in queue 1 */
job[1].queue = 1;
job[2].queue = 2; /* this job is in queue 2 */
...
etc
Итак, у вас есть «мешок с нитями». Поток просто выбирает работу - скажем, работу [2]. Если этому потоку разрешено обрабатывать только задания из очереди 1, он помещает это задание обратно в очередь готовности и выбирает другое задание.
Таким образом, каждый поток знает, какие очереди ему разрешено обрабатывать, и когда он выбирает задание, он проверяет, совпадает ли поле «очередь» задания. Если это не так, он выбирает другую работу.
(так во многих случаях работает планирование процессов в linux на нескольких ядрах. Каждый процесс имеет битовую маску, сообщающую, на каких процессорах ему разрешено работать, а затем процессор проверяет, что ему «разрешено» запускать этот процесс до того, как при этом.)