Простая многопоточность C++

Я пытаюсь создать поток на C++ (Win32) для запуска простого метода. Я новичок в потоках C++, но очень хорошо знаком с потоками в C#. Вот псевдокод того, что я пытаюсь сделать:

static void MyMethod(int data)
{
    RunStuff(data);
}

void RunStuff(int data)
{
    //long running operation here
}

Я хочу вызвать RunStuff из MyMethod без его блокировки. Каким будет самый простой способ запустить RunStuff в отдельном потоке?

Изменить: я также должен упомянуть, что хочу свести зависимости к минимуму. (Нет MFC ... и т. Д.)

Ответов (11)

Решение
#include <boost/thread.hpp>

static boost::thread runStuffThread;

static void MyMethod(int data)
{
    runStuffThread = boost::thread(boost::bind(RunStuff, data));
}

// elsewhere...
runStuffThread.join(); //blocks

Существует множество кроссплатформенных библиотек потоков C++ с открытым исходным кодом, которые вы могли бы использовать:

Среди них:

Поток Qt
Intel
TBB Boost

Как вы это описываете, я думаю, что подойдет Intel TBB или Boost thread.

Пример Intel TBB:

class RunStuff
{
public:
  // TBB mandates that you supply () operator  
  void operator ()()
  {
    // long running operation here
  }
};

// Here's sample code to instantiate it
#include <tbb/tbb_thread.h> 

tbb::tbb_thread my_thread(RunStuff);

Пример потока повышения:
http://www.ddj.com/cpp/211600441

Пример Qt:
http://doc.trolltech.com/4.4/threads-waitconditions-waitconditions-cpp.html
(я не думаю, что это соответствует вашим потребностям, но просто включено здесь для полноты; вам нужно унаследовать QThread, реализовать void run ( ) и вызовите QThread :: start ()):

Если вы программируете только на Windows и не заботитесь о кроссплатформе, возможно, вы могли бы напрямую использовать поток Windows:
http://www.codersource.net/win32_multithreading.html

Другая альтернатива - pthreads - они работают как в Windows, так и в Linux!

Только для win32 и без дополнительных библиотек вы можете использовать функцию CreateThread http://msdn.microsoft.com/en-us/library/ms682453(VS.85).aspx

Если вы действительно не хотите использовать сторонние библиотеки (я бы порекомендовал boost :: thread, как описано в других приложениях), вам необходимо использовать Win32API:

static void MyMethod(int data)
{

    int data = 3;

    HANDLE hThread = ::CreateThread(NULL,
        0,
        &RunStuff,
        reinterpret_cast<LPVOID>(data),
        0,
        NULL);


    // you can do whatever you want here

    ::WaitForSingleObject(hThread, INFINITE);
    ::CloseHandle(hThread);
}

static DWORD WINAPI RunStuff(LPVOID param)
{  

     int data = reinterpret_cast<int>(param);

     //long running operation here

     return 0;
}

Это безопасно:

unsigned __stdcall myThread(void *ArgList) {
//Do stuff here
}

_beginthread(myThread, 0, &data);

Нужно ли мне что-то делать, чтобы освободить память (например, CloseHandle) после этого вызова?

CreateThread (Win32) и AfxBeginThread (MFC) - это два способа сделать это.

Однако будьте осторожны при использовании _beginthread, если вам нужно использовать библиотеку времени выполнения C (CRT).

Простая многопоточность в C++ - это терминологическое противоречие!

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

Для минимального ответа (который на самом деле не предоставит вам все необходимое для синхронизации, но буквально отвечает на ваш вопрос) см.:

http://msdn.microsoft.com/en-us/library/kdzttdcb(VS.80).aspx

Также static означает что-то другое в C++.

CreateThread (Win32) и AfxBeginThread (MFC) - это два способа сделать это.

В любом случае подпись MyMethod должна немного измениться.

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

_beginthread и _beginthreadex - это функции библиотеки времени выполнения C и, согласно документации, эквивалентны System :: Threading :: Thread :: Start

Рассмотрите возможность использования пула потоков Win32 вместо создания новых потоков для рабочих элементов. Создание новых потоков является расточительным делом: каждый поток по умолчанию получает 1 МБ зарезервированного адресного пространства для своего стека, выполняет код запуска системного потока, вызывает доставку уведомлений почти в каждую DLL в вашем процессе и создает еще один объект ядра. Пулы потоков позволяют быстро и эффективно повторно использовать потоки для фоновых задач и будут увеличиваться или уменьшаться в зависимости от того, сколько задач вы отправляете. В общем, подумайте о создании выделенных потоков для бесконечных фоновых задач и используйте пул потоков для всего остального.

До Vista вы можете использовать QueueUserWorkItem. В Vista новые API пула потоков более надежны и предлагают несколько дополнительных возможностей. Каждый из них приведет к тому, что ваш фоновый код начнет работать в каком-то потоке пула потоков.

// Vista
VOID CALLBACK MyWorkerFunction(PTP_CALLBACK_INSTANCE instance, PVOID context);

// Returns true on success.
TrySubmitThreadpoolCallback(MyWorkerFunction, context, NULL);

// Pre-Vista
DWORD WINAPI MyWorkerFunction(PVOID context);

// Returns true on success
QueueUserWorkItem(MyWorkerFunction, context, WT_EXECUTEDEFAULT);

C++ 11, доступный с более поздними компиляторами, такими как Visual Studio 2013, имеет потоки как часть языка, а также довольно много других приятных кусочков, таких как лямбды.

Включаемый файл threads предоставляет класс потока, который представляет собой набор шаблонов. Функциональность потока находится в std:: пространстве имен. Некоторые функции синхронизации потоков используются std::this_thread в качестве пространства имен (см. Почему пространство имен std::this_thread? Для небольшого объяснения).

В следующем примере консольного приложения с использованием Visual Studio 2013 демонстрируются некоторые функции потоков C++ 11, включая использование лямбда-выражения (см. Что такое лямбда-выражение в C++ 11? ). Обратите внимание, что функции, используемые для ожидания потока, например std::this_thread::sleep_for(), используют продолжительность от std::chrono .

// threading.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>

int funThread(const char *pName, const int nTimes, std::mutex *myMutex)
{
    // loop the specified number of times each time waiting a second.
    // we are using this mutex, which is shared by the threads to
    // synchronize and allow only one thread at a time to to output.
    for (int i = 0; i < nTimes; i++) {
        myMutex->lock();
        std::cout << "thread " << pName << " i = " << i << std::endl;
        // delay this thread that is running for a second.  
        // the this_thread construct allows us access to several different
        // functions such as sleep_for() and yield().  we do the sleep
        // before doing the unlock() to demo how the lock/unlock works.
        std::this_thread::sleep_for(std::chrono::seconds(1));
        myMutex->unlock();
        std::this_thread::yield();
    }

    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    // create a mutex which we are going to use to synchronize output
    // between the two threads.
    std::mutex  myMutex;

    // create and start two threads each with a different name and a
    // different number of iterations. we provide the mutex we are using
    // to synchronize the two threads.
    std::thread myThread1(funThread, "one", 5, &myMutex);
    std::thread myThread2(funThread, "two", 15, &myMutex);

    // wait for our two threads to finish.
    myThread1.join();
    myThread2.join();

    auto  fun = [](int x) {for (int i = 0; i < x; i++) { std::cout << "lambda thread " << i << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); } };

    // create a thread from the lambda above requesting three iterations.
    std::thread  xThread(fun, 3);
    xThread.join();
    return 0;
}