     }
 
     /// Execute the given block while holding the lock.
-    public func withLock<T>(_ body: () throws -> T) throws -> T {
-        try lock()
+    public func withLock<T>(type: LockType = .exclusive, _ body: () throws -> T) throws -> T {
+        try lock(type: type)
         defer { unlock() }
         return try body()
     }

    /// Try to aquire a lock. This method will block until lock the already aquired by other process.
    ///
    /// Note: This method can throw if underlying POSIX methods fail.
    public func lock() throws {
      #if os(Windows)
        if handle == nil {
            let h = lockFile.pathString.withCString(encodedAs: UTF16.self, {
                CreateFileW(
                    $0,
                    UInt32(GENERIC_READ) | UInt32(GENERIC_WRITE),
                    0,
                    nil,
                    DWORD(OPEN_ALWAYS),
                    DWORD(FILE_ATTRIBUTE_NORMAL),
                    nil
                )
            })
            if h == INVALID_HANDLE_VALUE {
                throw FileSystemError(errno: Int32(GetLastError()))

        overlapped.Offset = 0
        overlapped.OffsetHigh = 0
        overlapped.hEvent = nil
        switch mode {
        case .exclusive:
            if !LockFileEx(handle, DWORD(LOCKFILE_EXCLUSIVE_LOCK), 0,
                           DWORD(INT_MAX), DWORD(INT_MAX), &overlapped) {
                throw ProcessLockError.unableToAquireLock(errno: Int32(GetLastError()))
            }
        case .shared:
            if !LockFileEx(handle, 0, 0,
                           DWORD(INT_MAX), DWORD(INT_MAX), &overlapped) {
                throw ProcessLockError.unableToAquireLock(errno: Int32(GetLastError()))
            }
        }
      #else
        // Open the lock file.
