0

我正在尝试使用多个线程(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);
        }
.....
}
4

2 回答 2

2

您正在使用“附加模式”打开文件。根据 C11:

使用附加模式('a'作为模式参数中的第一个字符)打开文件会导致所有后续对该文件的写入都被强制到当前的文件结尾,而不管对fseek函数的干预调用。

C 标准没有具体说明这应该如何实现,但在 POSIX 系统上,这通常是使用函数O_APPEND标志来实现的open,而刷新数据是使用函数完成的write。请注意,fseek您的代码中的调用应该无效。

我认为 POSIX 需要这个,因为它描述了 shell>>如何在附加模式 ( ) 中重定向输出:

附加的输出重定向将导致其名称由单词扩展产生的文件打开以在指定的文件描述符上输出。打开文件就像使用 O_APPEND 标志调用 POSIX.1-2008 的系统接口卷中定义的 open() 函数一样。如果该文件不存在,则应创建该文件。

而且由于大多数程序使用FILE接口向 发送数据stdout,这可能需要 在写入数据时fopen使用openwithO_APPENDwrite(而不是类似的函数)。pwrite

因此,如果在您的系统fopen上使用'a'模式使用O_APPEND和刷新完成使用write并且您的内核和文件系统正确实现O_APPEND标志,则使用互斥锁应该没有效果,因为写入不会干预

如果O_APPEND设置了文件状态标志的标志,则文件偏移量应在每次写入之前设置到文件末尾,并且在更改文件偏移量和写入操作之间不应发生中间文件修改操作。

请注意,并非所有文件系统都支持此行为。检查这个答案。


至于我对您上一个问题的回答,我的建议是删除互斥锁,因为它应该对文件的大小没有影响(而且它对我的机器没有任何影响)。

就个人而言,我从来没有真正使用过O_APPEND并且会犹豫这样做,因为它的行为可能在某种程度上不受支持,而且它的行为在 Linux 上很奇怪(参见 参考资料的“错误”部分pwrite)。

于 2018-03-20T09:50:57.207 回答
1

您肯定需要一个互斥锁,因为您要发出几个不同的文件命令。底层文件子系统不可能知道要调用多少个文​​件命令来完成整个操作。

所以你需要互斥锁。

在您的情况下,您可能会发现将互斥锁放在循环之外可以获得更好的性能。原因是,否则,线程之间的切换可能会导致磁盘不同部分之间的过度跳过。硬盘需要10ms移动读/写头,因此可能会大大减慢速度。

因此,对其进行基准测试可能是一个好主意。

于 2018-03-20T06:30:11.893 回答