Рассмотрим следующий фрагмент кода, работающего под Solaris 11.3:Multithreaded Printf против записи (2) буферизацию
void *run(void *args) {
int i;
for (i = 0; i < 100; i++) {
printf("Line #%d printed by child\n", i + 1);
}
}
int main() {
pthread_t tid;
int ret = pthread_create(&tid, NULL, run, NULL);
int i;
for (i = 0; i < 100; i++) {
printf("Line #%d printed by parent\n", i + 1);
}
pthread_exit(NULL);
}
После запуска, родительский поток всегда выводит все свои линии перед вновь созданной нити. Некоторые могут сказать, что pthread_create
слишком медленно, чтобы другой поток даже начал свою работу до того, как возвращается основной поток. Однако замена printf
на write(2)
дает ожидаемый выход, где потоки иногда чередуются с печатью своих линий.
Как можно объяснить это поведение?
Буферизация, безусловно, не имеет ничего общего с ним, поскольку вывод терминала по умолчанию буферизирован по строке; это должно быть справедливо как для write
, так и для printf
.
Даже если функции используют какую-то блокирующую технику для обеспечения безопасности потоков, что именно предотвратило бы выход из скремблирования?
Это _is_ проблема буферизации. Вы путаете 'write (2)' с 'fwrite (3)'. 'write (2)' является низкоуровневой функцией и не загружается. 'fwrite (3)' является 'stdio' функцией и буферизуется по умолчанию. Вы получаете этот эффект, потому что 'stdout' получает блок-буферизацию в фоновом потоке, в то время как он остается буферизированным в строке в родительском. Добавьте 'setbuf (stdout, NULL)' в оба потока и сравните. –
Выход другой нити по-прежнему идет на терминал, так что не следует ли это буферизовать по строке, как обычно? – ilkkachu
«Буферизация строк» является аспектом 'stdio', а не« terminal ». 'write (2)' не использует 'stdio' и поэтому не буферизуется. –