Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Синхронизация Managed и Unmanaged кода, 2 процесса через семафоры 
V
    Опции темы
neutrino
  Дата 16.12.2011, 16:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: 3
Всего: 62



Приветствую!

Есть два проекта: один на C# (гуй, WPF) и второй на C++. Оба проекта - отдельные процессы (екзешники). Процессы обмениваются данными через SharedMemory (т.е. MemoryMappedFile, т.к. в винде нет SM). Доступ к обшей структуре данных (очереди) синхронизируется с помощью двух семафоров. В общем ситуация довольно тривиальна: продьюсер-консюмер.

Для проверки межпроцессовой коммуникации я написал простой С++ код, который генерит случайные массивы и пишет их в структуру в SharedMemory. Для простоты длина очереди (каждый элемент в которой эта структура) задана 1 (одному), т.е. счетчик на семафоре тоже идет от 0 до 1 (бинарный семафор). В последствии это будет изменено на какой-то n.

Структура:
Код

typedef struct _SharedStruct {
    Bitrate bitrate;
    WCHAR consumerSemaphoreName[MUTEX_NAME_LENGTH];
    WCHAR producerSemaphoreName[MUTEX_NAME_LENGTH];
    int packetUID;
    BYTE sourceBufferChunk[BUFFER_CHUNK_SIZE];
    BYTE noiseBufferChunk[BUFFER_CHUNK_SIZE];
    BYTE cleanBufferChunk[BUFFER_CHUNK_SIZE];
} SHARED_STRUCT, *PSHARED_STRUCT;


Она же в C#:
Код

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    internal unsafe struct SharedStruct
    {
        // TODO! Error code!
        private const int SEMAPHORE_NAME_LENGTH = 256;
        private const int BUFFER_CHUNK_SIZE = 512;

        internal SamplingBitrate bitrate;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = SEMAPHORE_NAME_LENGTH)] 
        internal fixed char consumerSemaphoreName[SEMAPHORE_NAME_LENGTH];

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = SEMAPHORE_NAME_LENGTH)]
        internal fixed char producerSemaphoreName[SEMAPHORE_NAME_LENGTH];

        [MarshalAs(UnmanagedType.U4)]
        internal UInt32 packetUID;

        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = BUFFER_CHUNK_SIZE)]
        internal fixed byte inputBufferChunk[BUFFER_CHUNK_SIZE];

        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = BUFFER_CHUNK_SIZE)]
        internal fixed byte noiseBufferChunk[BUFFER_CHUNK_SIZE];

        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = BUFFER_CHUNK_SIZE)]
        internal fixed byte cleanBufferChunk[BUFFER_CHUNK_SIZE];
    }


Код заполнения структуры:
Код

    WCHAR* szName = L"Local\\ANSISS_SharedMemory";

    hMapFile = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, szName);
    pSharedStruct = (PSHARED_STRUCT) MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);
    
    hConsumedSemaphore = OpenSemaphoreW(SEMAPHORE_MODIFY_STATE, FALSE, pSharedStruct->consumerSemaphoreName);
    hProducedSemaphore = OpenSemaphoreW(SEMAPHORE_MODIFY_STATE, FALSE, pSharedStruct->producerSemaphoreName);

    for (int i = 0; i < 100; i++) {
        dwWaitResult = WaitForSingleObject(hConsumedSemaphore, INFINITE);
        Sleep(1000);
        // TODO: check if return result is WAIT_ABANDONED, WAIT_TIMEOUT, WAIT_OBJECT_0
        for (int j = 0; j < BUFFER_CHUNK_SIZE; j++) {
            pSharedStruct->sourceBufferChunk[j] = rand() % 256;
            pSharedStruct->cleanBufferChunk[j] = rand() % 256;
            pSharedStruct->noiseBufferChunk[j] = rand() % 256;
        }

        pSharedStruct->packetUID++;
        ReleaseSemaphore(hProducedSemaphore, 1, NULL);
        //Sleep(200);
    }

    UnmapViewOfFile(pSharedStruct);
    CloseHandle(hMapFile);
    CloseHandle(hConsumedSemaphore);
    CloseHandle(hProducedSemaphore);



Код считывания:
Код

            mConsumedSemaphore = new Semaphore(1, 1, CONSUMER_SEMAPHORE_NAME);
            mProducedSemaphore = new Semaphore(0, 1, PRODUCER_SEMAPHORE_NAME);
            mSharedMemory = new SharedMemory(4096); // one page
            mSharedStruct = (SharedStruct*)mSharedMemory.GetSharedMemory().ToPointer();
            CONSUMER_SEMAPHORE_NAME.CopyTo(mSharedStruct->consumerSemaphoreName);
            PRODUCER_SEMAPHORE_NAME.CopyTo(mSharedStruct->producerSemaphoreName);
            mSharedStruct->packetUID = 0;

            ...
            // Here we run the second (unmanaged) exe
            ...


            while (true)
            {
                if (mProducedSemaphore.WaitOne(Timeout.Infinite))
                {
                    Log("Read packet with UID: " + mSharedStruct->packetUID);

                    mConsumedSemaphore.Release(1); // ---> SemaphoreFullException !!!
                }
            }


Код на самом деле распределен по методам, я его собрал так, чтобы удобно было читать. 

При запуске вываливается эксепшен SemaphoreFullException в помеченной строке. Т.е. второй процесс не уменьшил счетчик семафора при WaitForSingleObject().

SharedMemory - класс написанный мной и являет собой обертку для MemoryMappedFile API винды, он работает. В частности он передает названия семафоров для синхронизации. Родной дотнетовский System.IO.MemoryMappedFiles.MemoryMappedFile редкостное Г. не позволяет делать то, для чего этот MMF и был придуман. Хэндлы семафоров в С++ коде получаются и никаких ошибок не возникает. Странно еще то, что С++ код бежит не взирая ни на что. Т.е. он выполняет свои 100 итераций и дохнет. А где синхронизация?

Что я упустил? Может я неправильно использую семафоры? Может дотнетовские семафоры невидны для unmanaged кода?

Спасибо!


--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
neutrino
Дата 17.12.2011, 16:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: 3
Всего: 62



Спасибо, ребята!

Люблю этот форум! smile Каждый раз, когда я пишу пост о какой-то проблеме, то почему-то направление а иногда и решение приходит в голову сразу. Видимо процесс объяснения проблемы кому-либо приводит к более глубокому пониманию.

Значит как я и написал, семафор созданный в managed коде был недоступен в unmanaged, т.к. не было задано атрибута SYNCHRONIZE на ряду с SEMAPHORE_MODIFY_STATE. Любая попытка сделать WaitForSingleObject() давала WAIT_FAILED, а GetLastError() возвращал ACCESS_DENIED. 

Вот и все. делов то! Добавляем атрибут SYNCHRONIZE:

Код

    hConsumedSemaphore = OpenSemaphoreW(SYNCHRONIZE, FALSE, pSharedStruct->consumerSemaphoreName);
    hProducedSemaphore = OpenSemaphoreW(SEMAPHORE_MODIFY_STATE | SYNCHRONIZE, FALSE, pSharedStruct->producerSemaphoreName);

И все работает!


--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.0596 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.