Есть много вещей, которые потенциально могут вызвать такое поведение.
Во-первых, какой у вас тип процессора? Если у вас процессор i7 или аналогичный, ОС увидит, что он имеет 8 ядер, тогда как на самом деле он имеет 4 ядра с 2 гиперпотоками / ядро. Для большинства операций гиперпоточность не обеспечивает такой же масштабируемости, как второе ядро, даже если ОС видит это таким образом. У меня было это, потому что мое общее использование ЦП показалось более низким для ОС ...
Во-вторых, возможно, у вас есть какая-то форма истинного обмена. Вы упоминаете, что у вас есть блокировка - даже если она сведена к минимуму, блокировки могут мешать вам эффективно планировать это.
Кроме того, прямо сейчас вы планируете все 100 рабочих элементов, сразу. ОС будет вынуждена постранично входить и выходить из этих 100 тем. Вы можете захотеть ограничить это только разрешением определенного числа для обработки в данное время. Это намного проще, если использовать новую библиотеку параллельных задач (просто используйте Parallel.ForEach с настройкой ParallelOptions, чтобы иметь максимальное количество потоков), но это можно сделать самостоятельно.
Учитывая, что вы планируете одновременную обработку всех 100 элементов, подкачка может затруднить получение максимальной пропускной способности.
Кроме того, если вы выполняете какую-либо другую «более реальную» работу - у вас могут возникнуть ложные проблемы с совместным использованием, особенно если вы работаете с массивами или коллекциями, которые являются общими (даже если элементы, которые вы обрабатываете, не являются общий).
Я бы порекомендовал запустить это под профилировщиком параллелизма в VS 2010 - это даст вам более четкую картину происходящего.