Windows Concepts: File Sharing Modes

Understanding how applications can access files concurrently.

Introduction to File Sharing

When multiple applications or processes need to access the same file, managing concurrent access becomes crucial. File sharing modes define how a file can be accessed by other processes while it is already open. This prevents data corruption, race conditions, and ensures data integrity. Windows provides a robust mechanism for controlling these access rights through file sharing modes.

When a process opens a file, it specifies not only the desired access (read, write, execute) but also the sharing mode. This mode informs the operating system about how other processes can access the file simultaneously.

Understanding Sharing Modes

The primary file sharing modes in Windows are defined by constants, typically used with functions like CreateFile:

These flags can be combined using the bitwise OR operator (|) to specify multiple sharing permissions.

FILE_SHARE_READ

If you specify FILE_SHARE_READ, it means that other processes can open the file for reading, even if your process currently has it open. This is common for configuration files or read-only data files.

FILE_SHARE_WRITE

If you specify FILE_SHARE_WRITE, it allows other processes to open the file for writing. This is less common for simultaneous writes to the same file and usually requires additional application-level synchronization to avoid conflicts.

FILE_SHARE_DELETE

This mode allows other processes to delete the file. If a process opens a file with FILE_SHARE_DELETE, another process can still delete it. The file will be marked for deletion and the handle will remain valid until the last process holding a handle to it closes it.

0 (No Sharing)

When you pass 0 as the sharing mode, the file is exclusively locked for the duration of the handle. No other process can open the file for reading, writing, or deletion. This is the strictest sharing mode and is useful when you need exclusive control over a file.

Common Scenarios and Examples

Scenario 1: Exclusive Access for Writing

A logging application needs to write to a log file. It's crucial that no other process can read or write to the log file while the logger is actively writing to prevent interleaved or corrupted log entries.

HANDLE hLogFile = CreateFile(
    TEXT("application.log"),
    GENERIC_WRITE,
    0, // No sharing - exclusive access
    NULL,
    CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL,
    NULL
);

if (hLogFile == INVALID_HANDLE_VALUE) {
    // Handle error
} else {
    // Write to the log file
    // ...
    CloseHandle(hLogFile);
}

Scenario 2: Allowing Reads While Writing

A configuration manager might need to update a configuration file. It's acceptable for other applications to read the configuration while it's being updated, as long as the updates are atomic or the readers can tolerate potentially stale data for a short period.

HANDLE hConfigFile = CreateFile(
    TEXT("config.ini"),
    GENERIC_WRITE | GENERIC_READ,
    FILE_SHARE_READ, // Allow other processes to read
    NULL,
    OPEN_ALWAYS,
    FILE_ATTRIBUTE_NORMAL,
    NULL
);

if (hConfigFile == INVALID_HANDLE_VALUE) {
    // Handle error
} else {
    // Update configuration
    // ...
    CloseHandle(hConfigFile);
}

Scenario 3: Allowing Reads and Writes

A database engine might need to update a data file but still allow other parts of the application (or different applications) to read from it simultaneously.

HANDLE hDataFile = CreateFile(
    TEXT("database.dat"),
    GENERIC_WRITE | GENERIC_READ,
    FILE_SHARE_READ | FILE_SHARE_WRITE, // Allow reads and writes
    NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    NULL
);

if (hDataFile == INVALID_HANDLE_VALUE) {
    // Handle error
} else {
    // Access and modify data
    // ...
    CloseHandle(hDataFile);
}
Important Note: Even with FILE_SHARE_WRITE, multiple processes writing to the exact same part of a file concurrently can lead to data corruption. Application-level locking mechanisms or transactional file operations might be necessary for robust concurrent writing.

Interaction with Other File Operations

The sharing mode specified when a file is opened affects subsequent attempts to open that same file. If a process attempts to open a file with a sharing mode that conflicts with a previously opened file's sharing mode, the CreateFile operation will fail, and GetLastError will return an error code such as ERROR_SHARING_VIOLATION.

CreateFile and Sharing Violations

Consider the following sequence:

  1. Process A opens myfile.txt with CreateFile, specifying dwShareMode = 0 (no sharing).
  2. Process B then attempts to open myfile.txt with CreateFile, specifying dwShareMode = FILE_SHARE_READ.
  3. Process B's attempt will fail because Process A has an exclusive lock (no sharing). GetLastError will return ERROR_SHARING_VIOLATION.

Conversely:

  1. Process A opens myfile.txt with CreateFile, specifying dwShareMode = FILE_SHARE_READ.
  2. Process B then attempts to open myfile.txt with CreateFile, specifying dwShareMode = 0 (no sharing).
  3. Process B's attempt will also fail with ERROR_SHARING_VIOLATION because Process A has indicated that other processes should be allowed to read, but not to open exclusively.

The key is that the sharing mode is a negotiation. The operating system grants access if the requested mode does not conflict with the modes already in use by open handles.

Best Practices