Как выполнить потоки в DLL в C - PullRequest
0 голосов
/ 10 января 2019

Я создал библиотеку DLL, в которой запущены 3 рабочих потока, и основной поток находится в цикле, ожидая завершения потоков. Потоки создаются, но выполнение потоков не выполняется.

Я попытался установить функции MessageBox внутри функции, которая создается с помощью CreateThread (), но поле не появляется. Я также попытался отладить, и возвращаемое значение из CreateThread () является допустимым, поэтому поток создается.

BOOL WINAPI DllMain() {
   main();
   return 1;
}

int main() {
    HANDLE h1, h2, h3;

    h1 = CreateThread(first)...
    h2 = CreateThread(second)...
    h3 = CreateThread(third)...

   WaitForSingleObject(h3, INFINITE);
   return 1;
}

first() {
    MessageBoxA("print some stuff");
    return;
}

Я включил псевдокод того, как выглядит мой макет. Я не могу предоставить реальный код из-за его чувствительности. Однако это то, что происходит. Я использую LoadLibrary в другом проекте, который загружает этот .DLL. DLL загружается и выполняется DllMain. Затем он вызывает мою основную функцию, которая создает 3 потока. Каждый поток создан. Но то, что внутри потока, не выполняется.

EDIT:

// dllmain.cpp : Defines the entry point for the DLL application.
#include <Windows.h>

void mb() {
    MessageBoxW(0, L"AAAAAAAAAAAAAAAAAAAAAAAAA", L"AAAAAAAAAAAAAAAAAAAAAAa", 1);
}

void create() {
    HANDLE han;
    DWORD threadId;
    han = CreateThread(NULL, 0, mb, NULL, 0, &threadId);
    han = CreateThread(NULL, 0, mb, NULL, 0, &threadId);
    han = CreateThread(NULL, 0, mb, NULL, 0, &threadId);

}

BOOL APIENTRY DllMain() {
    create();
    return 1;
}

Ответы [ 2 ]

0 голосов
/ 10 января 2019

, поскольку в общем случае DLL может быть выгружена, необходимо добавить ссылку на DLL - она ​​не будет выгружена до тех пор, пока не будет выполнен код, использующий ее код. это можно сделать с помощью вызова GetModuleHandleEx - увеличивает счетчик ссылок модуля, если не указано GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT. при выходе из потока - мы разыменовываем код DLL с помощью вызова FreeLibraryAndExitThread . ждать всех потоков выхода в большинстве случаев не нужно. поэтому код внутри dll может быть следующим

ULONG WINAPI DemoThread(void*)
{
    MessageBoxW(0, L"text", L"caption", MB_OK);
    // dereference dlll and exit thread
    FreeLibraryAndExitThread((HMODULE)&__ImageBase, 0);
}

void someFnInDll()
{
    HMODULE hmod;
    // add reference to dll, because thread will be use it
    if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (PCWSTR)&__ImageBase, &hmod))
    {
        if (HANDLE hThread = CreateThread(0, 0, DemoThread, 0, 0, 0))
        {
            CloseHandle(hThread);
        }
        else
        {
            // dereference dll if thread create fail
            FreeLibrary(hmod);
        }
    }
}

ожидание внутри точки входа в dll неверно, потому что мы держим здесь весь критический раздел процесса. если мы ждем выхода из потока - это ожидание всегда в тупике - поток до выхода (и запуска) попытается войти в этот критический раздел, но не может, потому что мы ждем его здесь. поэтому мы держим критическую секцию и ждем потоков (ы), но потоки ожидают, когда мы выйдем из этой критической секции. тупиковый

0 голосов
/ 10 января 2019

[MS.Docs]: точка входа в DllMain ( выделение - мое) состояния:

Вызов функций, которым требуются библиотеки DLL, отличные от Kernel32.dll, может привести к проблемам, которые трудно диагностировать . Например, вызов функций User, Shell и COM может вызвать ошибки нарушения доступа, поскольку некоторые функции загружают другие компоненты системы. И наоборот, вызов таких функций во время завершения может привести к ошибкам нарушения доступа, поскольку соответствующий компонент уже может быть выгружен или не инициализирован.

[MS.Docs]: функция MessageBox находится в User32.dll , поэтому Неопределенное поведение (имеется в виду, что в разных сценариях он может работать, работать некорректно или зависать).

Также, как заметил @RbMm, WaitForSingleObject не принадлежит там . Я не уверен насчет CreateThread (но я не смог найти официальный документ, чтобы подтвердить или опровергнуть его).

Просто из любопытства, не могли бы вы добавить printf("main called.\n"); в main , чтобы посмотреть, сколько раз он называется?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...