2

在下面的代码中,我的函数将数据条目写入磁盘,并且应该将偏移量返回到记录条目的文件中。但是,当在多个线程中运行代码时,我偶尔会发现这个值并不准确。此代码是否存在任何线程安全问题?

// global file descriptor to current data file, shared amongst many threads
FILE* current_fp;
pthread_mutex_t my_mutex;
...

int main()
{
    ...
    pthread_mutex_lock(&my_mutex);

    current_fp = fopen(data_file, "ab");
    if (current_fp == NULL)
    {
       fprintf(stderr, "%s: Unable to open file %s: %s\n", __func__, data_file, strerror_r(errno, ebuf, sizeof(ebuf)));
       pthread_mutex_unlock(&ldb_mutex);
       return -1;
    }

    pthread_mutex_unlock(&my_mutex);  

    return 0;
}

// write a data entry, and return the offset at which it will be stored
// I'm having an issue where it seems like *occasionally* the offset returned is not
// really the offset at which the entry was stored, with multiple threads
long write_log_entry(data_entry_t* entry)
{
   int num_written; 
   long offset; // offset at which entry will be written

   pthread_mutex_lock(&my_mutex);

   // get the next offset in the file, which is where I expect
   // the entry to be stored
   offset = ftell(current_fp);
   if (offset == -1)
   {
      error();
   }

   // an example -- the real code writes a bunch of data members of entry
   int num_written = fwrite(entry, sizeof(data_entry_t), 1, current_fp);
   if (num_written != 1) 
   {
       error();
   }

   fflush(current_fp);

   pthread_mutex_unlock(&my_mutex);

   return offset; 
}
4

2 回答 2

2

也许问题与 fopen 手册中描述的行为有关:

'请注意,ANSI C 要求文件定位函数在输出和输入之间进行干预,除非输入操作遇到文件结尾。(如果不满足此条件,则允许读取返回除最近写入之外的写入结果。)因此,放置 fseek(3) 或 fgetpos(3 ) 对此类流的写入和读取操作之间的操作。这个操作可能是一个明显的无操作(如 fseek(..., 0L, SEEK_CUR) 调用它的同步副作用。

ftell 可能被视为读取操作。尝试在 ftell 之前插入 fseek(..., 0L, SEEK_CUR) ,看看它是否有帮助。

于 2012-07-02T20:00:25.327 回答
0

由于您在打开文件之前没有锁定文件,因此它不是线程安全的。

任何其他进程都可以打开文件进行 I/O,但结果不可预测。

于 2012-07-02T18:11:56.790 回答