CreateThread заканчивается плохим выводом - PullRequest
0 голосов
/ 01 июля 2019

Я занимаюсь исследовательской работой по многопоточности. Я использую Win32Api для CreateThread. У меня есть массив символов, который содержит 5 букв дисков. Мне нужно MessageBox эти диски один за другим.

Вот мой код:

DWORD WINAPI Fun(LPVOID param)
{
const char* str = (const char*)param;
MessageBox(NULL, str, "hello", MB_OK | MB_ICONQUESTION);
return 0;
}

void StartWork()
{
int n, d, b = 0;
char dd;
DWORD dr = GetLogicalDrives();

HANDLE threads[26];

for (int i = 0; i < 26; i++)
{
    n = ((dr >> i) & 1);
    if (n == 1)
    {
        dd = char(65 + i);
        std::string text(1, dd);
        d = GetDriveType((text + ":\\").c_str());
        if (d == DRIVE_REMOVABLE || d == DRIVE_FIXED || d == DRIVE_REMOTE)
        {
            threads[b] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Evil, (LPVOID)text.c_str(), 0, NULL);
            b += 1;
        }
    }
}
WaitForMultipleObjects(b, threads, TRUE, 1000);
}

Вывод не то, что я хочу. Я получил только последнюю букву диска (у меня есть 3 диска - C, D, E, и мой вывод 3 раза msgbox "E")

1 Ответ

3 голосов
/ 01 июля 2019

Я предполагаю, что Evil - это Fun в вашем примере.Теперь код, который я собираюсь написать, не является хорошим современным кодом (хотя я использую C ++ 11, см. constexpr), но я надеюсь, что этого достаточно, чтобы показать вам проблему.string s должны сохраняться до конца программы (или, по крайней мере, до тех пор, пока все потоки не будут выполнены):

void StartWork()
{
  int n, d, b = 0;
  char dd;
  DWORD dr = GetLogicalDrives();

  constexpr std::size_t numMaxThreads = 26;
  HANDLE threads[numMaxThreads];

  //Now the strings survive until the end of the program, #include <array>
  std::array<std::string, numMaxThreads> texts;
  for (int i = 0; i < numMaxThreads; i++)
  {
    n = ((dr >> i) & 1);
    if (n == 1)
    {
        dd = char(65 + i);
        std::string text(1, dd);
        texts[b] = std::move(text);
        d = GetDriveType((texts[b] + ":\\").c_str());
        if (d == DRIVE_REMOVABLE || d == DRIVE_FIXED || d == DRIVE_REMOTE)
        {
            threads[b] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Fun, (LPVOID)texts[b].c_str(), 0, NULL);
            b += 1;
        }
    }
  }
  WaitForMultipleObjects(b, threads, TRUE, 1000);
}

Теперь, это хороший современный код?Нет, я бы порекомендовал использовать std::thread: это позволит вам лучше обрабатывать время жизни string с, что-то вроде этого

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

void Fun(const std::string& str)
{
    MessageBox(NULL, str.c_str(), "hello", MB_OK | MB_ICONQUESTION);
}

void StartWork()
{
    int n, d;
    char dd;
    DWORD dr = GetLogicalDrives();

    std::vector<std::thread> threads;

    for (int i = 0; i < 26; i++)
    {
        n = ((dr >> i) & 1);
        if (n == 1)
        {
            dd = char(65 + i);
            std::string text(1, dd);
            d = GetDriveType((text + ":\\").c_str());
            if (d == DRIVE_REMOVABLE || d == DRIVE_FIXED || d == DRIVE_REMOTE)
            {
                //thanks to zett42 for this simplification
                threads.emplace_back(Fun, text);
            }
        }
    }
    //We could be using for_each also
    for (auto& thread : threads) { thread.join(); }
}

Обратите внимание:

  1. С std::thread вы избегаете головной боли при управлении памятью, вы передаете владение памятью потоку, а затем поток отвечает за очистку
  2. Вы можете отказаться от использования пустых указателей и необходимостивручную подбрасывать вещи, повышая безопасность типов.

Редактировать: пользователь zett42 предложил более простую реализацию, и я обновил ответ.

...