Вы можете иметь простую структуру очереди - использовать любую структуру данных, которая вам нравится, - а затем просто использовать мьютекс при добавлении / удалении элементов из него.
Если ваши потоки перехватят работу, которую они должны выполнить, в достаточно больших "кусках", тогда будет очень мало конфликтов на мьютексе, поэтому очень мало служебных данных.
Например, если каждый поток должен был захватывать приблизительно 1 секунду работы за раз и работать независимо в течение 1 секунды, тогда с мьютексом было бы очень мало операций.
Потоки могли выходить, когда у них больше не было работы; основной поток может затем ждать, используя pthread_join.