Нужен ли нам мьютекс для выполнения многопоточности ввода-вывода файла

Я пытаюсь сделать случайную запись (тест производительности) в файл, используя несколько потоков (pthread). Похоже, если я закомментирую mutex lock размер созданного файла меньше фактического, как будто некоторые записи теряются (всегда в несколько кратных размеру куска). Но если я оставлю мьютекс, это всегда точный размер.

Есть ли в моем коде проблема в другом месте и мьютекс на самом деле не требуется (как предложено @evan) или мьютекс нужен здесь

void *DiskWorker(void *threadarg) {

FILE *theFile = fopen(fileToWrite, "a+");
....
for (long i = 0; i < noOfWrites; ++i) {
//pthread_mutex_lock (&mutexsum);
// For Random access

fseek ( theFile , randomArray[i] * chunkSize  , SEEK_SET );
fputs ( data , theFile );

//Or for sequential access (in this case above 2 lines would not be here)

fprintf(theFile, "%s", data);
//sequential access end

fflush (theFile);
//pthread_mutex_unlock(&mutexsum);
}
.....
}

0

Решение

Вам определенно нужен мьютекс, потому что вы запускаете несколько разных файловых команд. Базовая файловая подсистема не может знать, сколько файловых команд вы собираетесь вызвать для завершения всей вашей операции.

Так что вам нужен мьютекс.

В вашей ситуации вы можете обнаружить, что вы получаете лучшую производительность, применяя мьютекс вне петля. Причина в том, что в противном случае переключение между потоками может привести к чрезмерному пропуску между различными частями диска. Жесткие диски занимают около 10ms перемещать головку чтения / записи, чтобы потенциально сильно замедлить процесс.

Так что это может быть хорошей идеей для сравнения.

1

Другие решения

Вы открываете файл, используя «режим добавления». Согласно C11:

Открытие файла в режиме добавления ('a' как первый персонаж в
аргумент mode) заставляет принудительно выполнять все последующие записи в файл
на текущий текущий конец файла, независимо от промежуточных вызовов
fseek функция.

Стандарт C не определяет, как именно это должно быть реализовано, но в системе POSIX это обычно реализуется с использованием O_APPEND флаг open функция, а сброс данных выполняется с помощью функции write, Обратите внимание, что fseek Звонок в вашем коде не должен иметь никакого эффекта.

Я думаю, что POSIX требует этого, так как он описывает, как перенаправить вывод в режиме добавления (>>) сделано оболочка:

При добавлении перенаправления вывода должен появиться файл, имя которого приводит к
от раскрытия слова, которое будет открыто для вывода на назначенный
дескриптор файла. Файл открывается так, как будто функция open () как
определенный в томе системных интерфейсов POSIX.1-2008 был назван
с флагом O_APPEND. Если файл не существует, он должен быть
создано.

И так как большинство программ используют FILE интерфейс для отправки данных stdoutэто наверное требует fopen использовать open с O_APPEND а также write (а не такие функции, как pwrite) при записи данных.

Так что если в вашей системе fopen с 'a' режим использует O_APPEND и промывка производится с помощью write и ваше ядро ​​и файловая система правильно реализуют O_APPEND флаг, использование мьютекса не должно иметь никакого эффекта при записи не вмешивайся:

Если O_APPEND установлен флаг состояния файла, установлен файл
смещение должно быть установлено до конца файла перед каждой записью, и нет
промежуточная операция изменения файла должна происходить между изменениями
смещение файла и операция записи.

Обратите внимание, что не все файловые системы поддерживают это поведение. Проверьте этот ответ.


Что касается моего ответа на ваш предыдущий вопрос, я предложил удалить мьютекс, так как он не должен влиять на размер файла (и это никак не повлияло на мою машину).

Лично я никогда не использовал O_APPEND и не решился бы сделать это, так как его поведение может не поддерживаться на каком-то уровне, плюс его поведение странно в Linux (см. раздел «Ошибки» в pwrite).

2

По вопросам рекламы [email protected]