Как заставить поток Windows работать с двумя функциями одновременно?

Вопрос прост, но решение ускользает от меня. Я хочу, чтобы две функции вызывались и выполнялись одновременно (в отдельных потоках), но я могу получить только void function1() называется и void function2() работает только потом не во время. Я установил привязку потоков к процессорам 1 и 2 (у меня есть многоядерный процессор, надеюсь, у вас тоже есть).

Я вижу, что одновременно вызывается только одна функция, просто потому, что я получаю вывод только function 1 тогда как обычно я видел бы смесь function 1 а также function 2,

Не стесняйтесь переставлять код, чтобы сделать его работоспособным, однако, пожалуйста, постарайтесь сохранить оригинальную методологию без изменений в том, как функция вызывается потоком в классе. Вот полный код.

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <iostream>

class thread_class
{
    private:


    public:

    void function1()
    {
        for(int count = 0; count < 1000; count++)
            std::cout<<"function 1"<<std::endl;
    }
    void function2()
    {
        for(int count = 0; count < 1000; count++)
            std::cout<<"function 2"<<std::endl;
    }
    thread_class(){}
    ~thread_class(){}
    DWORD_PTR WINAPI threadMain0()
    {
        function1();

        return 0;
    }
    DWORD_PTR WINAPI threadMain1()
    {
        function2();

        return 0;
    }
    void thread()
    {
        HANDLE *m_threads = NULL;
        DWORD_PTR c = 2;

        m_threads = new HANDLE[c];

        DWORD_PTR i = 0;
        DWORD_PTR m_id0 = 0;
        DWORD_PTR m_mask0 = 1 << i;

        m_threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadMain0(), (LPVOID)i, NULL, &m_id0);
        SetThreadAffinityMask(m_threads[i], m_mask0);

        wprintf(L"Creating Thread %d (0x%08x) Assigning to CPU 0x%08x\r\n", i, (LONG_PTR)m_threads[i], m_mask0);

        i = 1;
        DWORD_PTR m_id1 = 0;
        DWORD_PTR m_mask1 = 1 << i;

        m_threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadMain1(), (LPVOID)i, NULL, &m_id1);
        SetThreadAffinityMask(m_threads[i], m_mask1);

        wprintf(L"Creating Thread %d (0x%08x) Assigning to CPU 0x%08x\r\n", i, (LONG_PTR)m_threads[i], m_mask1);
    }
};
int main()
{
    thread_class* MAIN_THREADS;

    MAIN_THREADS = new thread_class();

    MAIN_THREADS->thread();

    delete MAIN_THREADS;

    return 0;
}

редактировать: это слегка измененная версия кода ниже, которая показывает, что он не работает параллельно.

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <iostream>

class thread_class
{
    private:


    public:

    void function1()
    {
        int exit = 0;

        while(exit == 0)
        {
            std::cout<<"enter 1 to exit:"<<std::endl;
            std::cin>>exit;
        };
    }
    void function2()
    {
        for(int count = 0; count < 1000; count++)
            std::cout<<"function 2"<<std::endl;
    }
    thread_class(){}
    ~thread_class(){}
    DWORD_PTR WINAPI threadMain0()
    {
        function1();

        return 0;
    }
    DWORD_PTR WINAPI threadMain1()
    {
        function2();

        return 0;
    }
    void thread()
    {
        HANDLE *m_threads = NULL;
        DWORD_PTR c = 2;

        m_threads = new HANDLE[c];

        DWORD_PTR i = 0;
        DWORD_PTR m_id0 = 0;
        DWORD_PTR m_mask0 = 1 << i;

        m_threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadMain0(), (LPVOID)i, NULL, &m_id0);
        SetThreadAffinityMask(m_threads[i], m_mask0);

        wprintf(L"Creating Thread %d (0x%08x) Assigning to CPU 0x%08x\r\n", i, (LONG_PTR)m_threads[i], m_mask0);

        i = 1;
        DWORD_PTR m_id1 = 0;
        DWORD_PTR m_mask1 = 1 << i;

        m_threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadMain1(), (LPVOID)i, NULL, &m_id1);
        SetThreadAffinityMask(m_threads[i], m_mask1);

        wprintf(L"Creating Thread %d (0x%08x) Assigning to CPU 0x%08x\r\n", i, (LONG_PTR)m_threads[i], m_mask1);
    }
};
int main()
{
    thread_class* MAIN_THREADS;

    MAIN_THREADS = new thread_class();

    MAIN_THREADS->thread();

    delete MAIN_THREADS;

    return 0;
}

2 ответа

Решение

Итак, несколько вещей:

1) Вы не можете использовать обычные функции-члены в качестве ThreadProc. Если вам нужно привести его к компиляции, вероятно, это неправильно. Функции ThreadProc должны быть свободными или статичными. Они также имели неправильную подпись, поскольку ThreadProc принимает один параметр void*.

2) Есть несколько мест, где вы используете DWORD_PTR, когда вы действительно хотите DWORD, например, возвращаемое значение из ThreadProc, c, i, так далее.

3) Из CreateProcess документы:

A thread in an executable that calls the C run-time library (CRT) should use the _beginthreadex and _endthreadex functions for thread management rather than CreateThread and ExitThread; this requires the use of the multithreaded version of the CRT. If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions.

Шансы пишут cout в итоге попадает в ЭЛТ. Это может не произойти, и даже если это произойдет, у вас могут не быть проблем, но если вы это сделаете, это хорошее место, чтобы посмотреть.

4) I / O не гарантируется чередование вообще, поэтому запись в cout не очень хороший способ решить, работают ли потоки одновременно или нет. Я добавил немного Sleep вызовы потоков, а также создание их сначала приостановлено, чтобы я мог запустить их как можно ближе друг к другу, чтобы создать впечатление, что ввод-вывод чередуется, но это может быть просто совпадением. Однажды я вижу, что вы также можете понять, что правильно, когда потоки запускаются, строка, которая печатается, и endl не привязаны друг к другу, то есть я вижу обе строки, за которыми следуют два конца строки. После этого это несколько чередуется.

5) Вы всегда хотите дождаться завершения потоков, прежде чем удалить класс из-под них. Вы также обычно хотите закрыть их ручки, как только они будут сделаны.

Я исключил конструктор / деструктор, так как они были пустыми и другими пухами, просто чтобы это было как можно короче.

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <iostream>

class thread_class
{
    public:
    void function1()
    {
        Sleep(0);
        for(int count = 0; count < 10; count++)
        {
            std::cout<<"function 1"<<std::endl;
            Sleep(0);
        }
    }
    void function2()
    {
        Sleep(0);
        for(int count = 0; count < 10; count++)
        {
            std::cout<<"function 2"<<std::endl;
            Sleep(0);
        }
    }
    static DWORD WINAPI threadMain0(LPVOID param)
    {
        thread_class* This = static_cast<thread_class*>(param);
        This->function1();
        return 0;
    }
    static DWORD WINAPI threadMain1(LPVOID param)
    {
        thread_class* This = static_cast<thread_class*>(param);
        This->function2();
        return 0;
    }
    void thread()
    {
        HANDLE m_threads[2] = {};
        DWORD threadIDs[2] = {};
        LPTHREAD_START_ROUTINE threadProcs[2] = {threadMain0, threadMain1};
        DWORD_PTR mask = 0;
        for(int i = 0; i < 2; ++i)
        {
            m_threads[i] = CreateThread(NULL, 0, threadProcs[i], this, CREATE_SUSPENDED, &threadIDs[i]);
            mask = 1 << i;
            SetThreadAffinityMask(m_threads[i], mask);
            wprintf(L"Creating Thread %d (0x%08p) Assigning to CPU 0x%08p\r\n", i, m_threads[i], mask);
        }
        for(int i = 0; i < 2; ++i)
        {
            ResumeThread(m_threads[i]);
        }
        WaitForMultipleObjects(2, m_threads, TRUE, INFINITE);
        for(int i = 0; i < 2; ++i)
        {
            CloseHandle(m_threads[i]);
        }
    }
};

int main()
{
    thread_class* MAIN_THREADS;
    MAIN_THREADS = new thread_class();
    MAIN_THREADS->thread();
    delete MAIN_THREADS;
    return 0;
}

Одной из проблем, которые я вижу в обеих версиях вашего кода, является NULL, передаваемый параметру dwCreationFlags функции CreateThread(). Это означает, что созданный поток будет запущен сразу после выхода из CreateThread() (или даже раньше, если у вас есть многоядерный процессор и удачное планирование). Таким образом, кажется, что ваш первый поток заканчивает свою работу до того, как второй поток сможет родиться (потому что создание потока является дорогостоящей операцией с точки зрения времени - десятков или сотен миллисекунд).

Поэтому не могли бы вы попробовать следующее:

  1. Создайте обе темы с флагом CREATE_SUSPENDED вместо NULL
  2. Затем вызовите ResumeThread для обоих потоков.
  3. Увеличьте время выполнения функций (возможно, миллионы итераций).
Другие вопросы по тегам