Почему версия кода.Net зависает, а C++ нет?

Почему тот же код в.Net (C#) зависает, а в C++ - нет? На самом деле проблема в System.IO.FileStream, но я сократил его до CreateFile, тем не менее, он все еще висит в.Net (хотя он почти на 100% аналогичен коду C++):

using System;
using System.Runtime.InteropServices;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static IntPtr _handle;

        static void Main()
        {
            _handle = CreateFile("test.txt", GENERIC_READ | GENERIC_WRITE,
                FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero,
                OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);

            new Thread(MyProc) { IsBackground = true }.Start();
            new Thread(MyProc) { IsBackground = true }.Start();

            Console.ReadKey();
        }

        static void MyProc()
        {
            for (int i = 0; i < int.MaxValue; i++)
            {
                Console.WriteLine(i);

                var _overlapped = new NativeOverlapped();

                LockFileEx(_handle, LOCKFILE_EXCLUSIVE_LOCK, 0, int.MaxValue, int.MaxValue, ref _overlapped);

                Thread.Sleep(50);

                UnlockFileEx(_handle, 0, int.MaxValue, int.MaxValue, ref _overlapped);
            }
        }

        public const int LOCKFILE_EXCLUSIVE_LOCK = 0x00000002;

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool LockFileEx(IntPtr hFile, int flags, int reserved, int numberOfBytesToLockLow, int numberOfBytesToLockHigh,
            ref NativeOverlapped overlapped);

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool UnlockFileEx(IntPtr hFile, int reserved, int numberOfBytesToUnlockLow, int numberOfBytesToUnlockHigh,
            ref NativeOverlapped overlapped);

        public const int GENERIC_READ = unchecked((int)0x80000000L);
        public const int GENERIC_WRITE = (int)0x40000000L;

        public const int OPEN_ALWAYS = 4;

        public const int FILE_SHARE_READ = 0x00000001;
        public const int FILE_SHARE_WRITE = 0x00000002;
        public const int FILE_SHARE_DELETE = 0x00000004;

        public const int FILE_ATTRIBUTE_NORMAL = 0x00000080;

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr CreateFile(string fileName, int desiredAccess, int shareMode,
            IntPtr pSecurityAttributes, int creationDisposition, int flagsAndAttributes, IntPtr hTemplateFile);
    }
}

А вот версия C++, которая не зависает:

#include "stdafx.h"

#include <thread>
#include <Windows.h>

HANDLE hFile;

DWORD WINAPI MyProc(LPVOID lpParam);

int _tmain(int argc, _TCHAR* argv[])
{
    hFile = CreateFile(L"test.txt", GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  

    HANDLE hThread1 = CreateThread(NULL, 0, MyProc, NULL, 0, NULL);
    HANDLE hThread2 = CreateThread(NULL, 0, MyProc, NULL, 0, NULL);

    int ch = getchar();

    return 0;
}

DWORD WINAPI MyProc(LPVOID lpParam)
{
    for(int i = 0; i < INT_MAX; i++)
    {
        printf("%d\r\n", i);

        OVERLAPPED overlapped = {0};

        LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, INT_MAX, INT_MAX, &overlapped);

        Sleep(50);

        UnlockFileEx(hFile, 0, INT_MAX, INT_MAX, &overlapped);
    }

    return 0;
}

1 ответ

Решение

Похоже, недопустимо дважды вызывать LockFileEx с LOCKFILE_EXCLUSIVE_LOCK для одного и того же дескриптора файла. Это должны быть разные файловые дескрипторы или какая-то внутренняя синхронизация для дескриптора.

Тревожно то, что в документации MSDN нет однозначности этого вопроса. И нет четкого сообщения об ошибке во время выполнения. Более того, мне кажется, что проблема воспроизводится только на моем компьютере. Это некрасиво.

Другие вопросы по тегам