Существуют ли эквиваленты pread на разных платформах?

Я пишу параллельную постоянную очередь сообщений на С++, которая требует одновременного доступа для чтения к файлу без использования отображения памяти io. Короткая история заключается в том, что несколько потоков должны будут читать с разных смещений файла.

Первоначально у меня был файловый объект с типичными методами чтения/записи, и потоки получали мьютекс для вызова этих методов. Однако так получилось, что я где-то неправильно захватил мьютекс, из-за чего один поток переместил смещение файла во время чтения/записи, а другой поток начал чтение/запись в неправильную часть файла.

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

Я хотел бы использовать что-то вроде pread, что позволяет передавать текущее смещение для функций чтения/записи.

Однако эта функция доступна только в Linux, и мне нужны эквивалентные реализации для Windows, AIX, Solaris и HPUX, какие-либо предложения?


person Snazzer    schedule 20.04.2009    source источник
comment
Почему вы не можете написать свой pread() для других платформ? Кажется, там нет ничего, что вы не могли бы сделать с функцией типа fseek().   -  person Duck    schedule 20.04.2009
comment
@Duck: Snazzer хочет что-то, что будет искать и читать за одну атомарную операцию.   -  person Chris Jester-Young    schedule 20.04.2009
comment
Страница руководства не указывает, что pread() делает это. Будет ли какая-либо система предлагать атомарный поиск/чтение в обычном файле? Даже используя pread(), он должен был бы предоставить свою собственную блокировку, прежде чем вызывать ее.   -  person Duck    schedule 20.04.2009
comment
pread принимает смещение в качестве параметра, поэтому я предполагаю, что он позволяет выполнять атомарные операции поиска, а затем чтения/записи в дескрипторе общего файла. Гугление, кажется, указывает на это... или я что-то упустил? В противном случае, похоже, мало пользы от pread, если его нельзя использовать с несколькими потоками.   -  person Snazzer    schedule 20.04.2009
comment
@Snazzer: Мои извинения. Это атомарно и на самом деле довольно круто. Мне нужно поиграть с ним еще немного.   -  person Duck    schedule 20.04.2009


Ответы (3)



В NIO у java.nio.channels.FileChannel есть метод read(ByteBuffer dst, long position), который внутренне использует pread.

Ой, подождите, ваш вопрос касается C++, а не Java. Что ж, я только что посмотрел исходный код JDK, чтобы увидеть, как он это делает для Windows, но, к сожалению, в Windows он не является атомарным: он просто ищет, затем читает, а затем ищет обратно.

Для платформ Unix изюминкой является то, что pread является стандартным для любой операционной системы, поддерживающей XSI (по-видимому, X/Open System Interface): http://www.opengroup.org/onlinepubs/009695399/functions/pread.html

person Chris Jester-Young    schedule 20.04.2009

Основываясь на другом ответе, самое близкое, что я мог придумать, это это. Однако есть ошибка: ReadFile изменит смещение файла, а pread гарантированно не изменит смещение файла. Нет никакого реального способа исправить это, потому что код может выполнять обычные операции чтения() и записи() одновременно без блокировки. Кто-нибудь нашел звонок, который не изменит смещение?

unsigned int FakePRead(int fd, void *to, std::size_t size, uint64_offset) {
  // size_t might be 64-bit.  DWORD is always 32.
  const std::size_t kMax = static_cast<std::size_t>(1UL << 31);
  DWORD reading = static_cast<DWORD>(std::min<std::size_t>(kMax, size));
  DWORD ret;
  OVERLAPPED overlapped;
  memset(&overlapped, 0, sizeof(OVERLAPPED));
  overlapped.Offset = static_cast<DWORD>(off);
  overlapped.OffsetHigh = static_cast<DWORD>(off >> 32);
  if (!ReadFile((HANDLE)_get_osfhandle(fd), to, reading, &ret, &overlapped)) {
    // TODO: set errno to something?
    return -1;
  }
  // Note the limit to 1 << 31 before.
  return static_cast<unsigned int>(ret);
}
person Kenneth Heafield    schedule 21.01.2013
comment
FWIW, я смог подтвердить, что ReadFile() действительно изменяет смещение файла, по крайней мере, в Windows 7. Я использовал SetFilePointerEx() для чтения смещения. - person kainjow; 16.12.2014