Простой пример многопоточности в C ++

357

Может ли кто-нибудь опубликовать простой пример запуска двух (объектно-ориентированных) потоков в С++.

Я ищу актуальные объекты потока С++, которые я могу расширить методы запуска (или что-то подобное), в отличие от вызова библиотеки потоков C-стиля.

Обновление. Я отказался от каких-либо конкретных запросов ОС в надежде, что тот, кто ответил, ответит на использование библиотек кросс-платформ. Я просто делаю это явным.

  • 6
    @SamuelLiew это не должно быть закрыто. Вопрос был задан в 2008 году Тогда C ++ не имеют резьбу , и не было никакой простой пример. Только обертки вокруг специфичных для ОС вызовов C.
Теги:
multithreading

8 ответов

473
Лучший ответ

Создайте функцию, которую вы хотите выполнить, например:

void task1(std::string msg)
{
    std::cout << "task1 says: " << msg;
}

Теперь создайте объект thread, который в конечном итоге вызовет функцию выше, например:

std::thread t1(task1, "Hello");

(Для доступа к классу std::thread необходимо #include <thread>)

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

Если позже вы хотите дождаться выполнения потока, выполняющего эту функцию, вызовите:

t1.join(); 

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


Код

#include <string>
#include <iostream>
#include <thread>

using namespace std;

// The function we want to execute on the new thread.
void task1(string msg)
{
    cout << "task1 says: " << msg;
}

int main()
{
    // Constructs the new thread and runs it. Does not block execution.
    thread t1(task1, "Hello");

    // Do other things...

    // Makes the main thread wait for the new thread to finish execution, therefore blocks its own execution.
    t1.join();
}

Дополнительная информация о std :: thread here

  • В GCC скомпилируйте с -std=c++0x -pthread.
  • Это должно работать для любой операционной системы, если ваш компилятор поддерживает эту функцию (С++ 11).
  • 0
    @Ken: Будет ли это работать для Linux и Windows?
  • 0
    @ user2568508 Находясь в стандартной библиотеке, так и должно быть, да. Хотя вам придется приобрести компилятор с этой поддержкой.
Показать ещё 17 комментариев
79

Ну, технически любой такой объект будет построен поверх библиотеки потоков C-стиля, потому что С++ только что указала запас std::thread модель в С++ 0x, которая была просто прибита и еще не реализована. Проблема несколько системная, технически существующая модель памяти С++ не является достаточно строгой, чтобы допускать четко определенную семантику для всех случаев "случится раньше". Ханс Бем написал статью по теме некоторое время назад и сыграл важную роль в том, чтобы выбить стандарт С++ 0x по теме.

http://www.hpl.hp.com/techreports/2004/HPL-2004-209.html

Тем не менее, существует несколько кросс-платформенных библиотек С++, которые отлично работают на практике. Блоки построения потоков Intel содержат объект tbb:: thread, который близко аппроксимирует стандарт С++ 0x, а Boost имеет библиотеку boost:: thread, которая делает то же самое.

http://www.threadingbuildingblocks.org/

http://www.boost.org/doc/libs/1_37_0/doc/html/thread.html

Используя boost:: thread, вы получите что-то вроде:

#include <boost/thread.hpp>

void task1() { 
    // do stuff
}

void task2() { 
    // do stuff
}

int main (int argc, char ** argv) {
    using namespace boost; 
    thread thread_1 = thread(task1);
    thread thread_2 = thread(task2);

    // do other stuff
    thread_2.join();
    thread_1.join();
    return 0;
}
  • 8
    Ускорение потока - это здорово - моя единственная проблема состояла в том, что вы не могли (когда я в последний раз использовал его) на самом деле получить доступ к собственному дескриптору основного потока, поскольку он был членом частного класса! В win32 есть тонна вещей, для которых вам нужен дескриптор потока, поэтому мы настроили его, чтобы сделать дескриптор общедоступным.
  • 3
    Другая проблема с boost :: thread заключается в том, что, насколько я помню, у вас нет свободы устанавливать размер стека нового потока - функция, к сожалению, также не включенная в стандарт c ++ 0x.
Показать ещё 3 комментария
18

Существует также библиотека POSIX для операционных систем POSIX. Проверьте совместимость

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <iostream>

void *task(void *argument){
      char* msg;
      msg = (char*)argument;
      std::cout<<msg<<std::endl;
}

int main(){
    pthread_t thread1, thread2;
    int i1,i2;
    i1 = pthread_create( &thread1, NULL, task, (void*) "thread 1");
    i2 = pthread_create( &thread2, NULL, task, (void*) "thread 2");

    pthread_join(thread1,NULL);
    pthread_join(thread2,NULL);
    return 0;

}

скомпилировать с -lpthread

http://en.wikipedia.org/wiki/POSIX_Threads

10

Вот более надежный способ создания произвольного количества потоков (в С++ 11 или новее):

#include <thread>
#include <iostream>
using namespace std;

void doSomething(int id) {
    cout << "Thread id = " << id;
}

/**
 * Spawns n threads
 */
void spawnThreads(int n)
{
    thread threads[n];
    // spawn n threads:
    for (int i = 0; i < n; i++) {
        threads[i] = thread(doSomething, i + 1);
    }

    for (auto& th : threads) {
        th.join();
    }
}
7

В значительной степени это зависит от библиотеки, которую вы решили использовать. Например, если вы используете библиотеку wxWidgets, создание потока будет выглядеть так:

class RThread : public wxThread {

public:
    RThread()
        : wxThread(wxTHREAD_JOINABLE){
    }
private:
    RThread(const RThread &copy);

public:
    void *Entry(void){
        //Do...

        return 0;
    }

};

wxThread *CreateThread() {
    //Create thread
    wxThread *_hThread = new RThread();

    //Start thread
    _hThread->Create();
    _hThread->Run();

    return _hThread;
}

Если ваш основной поток вызывает метод CreateThread, вы создадите новый поток, который начнет выполнять код в вашем методе "Enter". В большинстве случаев вам нужно будет ссылаться на поток, чтобы присоединиться или остановить его. Подробнее здесь: документация wxThread

  • 0
    Вы забыли удалить тему. Возможно, вы хотели создать отдельную тему?
  • 0
    Да, верно, я извлек код из некоторого кода, над которым я сейчас работаю, и, конечно, ссылка на поток хранится где-то, чтобы присоединиться, остановить и удалить его позже. Благодарю. :)
6

При поиске примера класса С++, который вызывает один из своих методов экземпляра в новом потоке, этот вопрос возникает, но мы не смогли использовать какой-либо из этих ответов таким образом. Вот пример, который делает это:

Class.h

class DataManager
{
public:
    bool hasData;
    void getData();
    bool dataAvailable();
};

Class.cpp

#include "DataManager.h"

void DataManager::getData()
{
    // perform background data munging
    hasData = true;
    // be sure to notify on the main thread
}

bool DataManager::dataAvailable()
{
    if (hasData)
    {
        return true;
    }
    else
    {
        std::thread t(&DataManager::getData, this);
        t.detach(); // as opposed to .join, which runs on the current thread
    }
}

Обратите внимание, что этот пример не попадает в мьютекс или блокировку.

  • 0
    Спасибо за публикацию этого. Обратите внимание, что общая форма вызова потока в методе экземпляра выглядит примерно так: Foo f; std :: thread t (& Foo :: Run, & f, args ...); (где Foo - это класс, в котором функция Run () имеет функцию-член).
4

Если в глобальных именах не требуется отдельная функция, мы можем использовать лямбда-функции для создания потоков.

Одним из основных преимуществ создания потока с использованием лямбда является то, что нам не нужно передавать локальные параметры в виде списка аргументов. Мы можем использовать список захвата для того же самого, и свойство закрытия lambda позаботится о жизненном цикле.

Вот пример кода

int main() {
    int localVariable = 100;

    thread th { [=](){
        cout<<"The Value of local variable => "<<localVariable<<endl;
    }}

    th.join();

    return 0;
}

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

0

//multithread.cpp: простой пример потоковой обработки в C++, который использует потоки и критический раздел.

#include "stdafx.h"
#include <thread>
#include <iostream>
#include<fstream>
#include <windows.h>

using namespace std;


bool flag = 1;
auto path = "D:\\temp";
void writestatus(int i, int j);
CRITICAL_SECTION cs;

void workerThread(int j)
{
    int i = 1;
    ofstream f2;
    char buff[150] = { 0 };
    while (flag)
    {
        sprintf_s(buff, 150, "D:\\temp\\MyTemp_%d%03d.txt", j, i++);

        //str.append("%d", i++);
        f2.open(buff);
        f2 << buff;
        f2.close();
        //Sleep(10);
    }
    EnterCriticalSection(&cs);
    writestatus(i, j);
    LeaveCriticalSection(&cs);
}

void writestatus(int i, int j)
{
    ofstream f1;
    char buff[150] = { 0 };
    f1.open("D:\\temp\\status.txt", ios_base::app);
    sprintf_s(buff, 150, "%d Writes %d files \n", j, i++);
    if (f1)
    {
        f1 << buff;
    }
    else
    {
        MessageBeep(1);
    }
    f1.close();
}

int main()
{
    system("del d:\\temp\\*.txt");

    InitializeCriticalSection(&cs);
    thread t1(workerThread, 1);
    thread t2(workerThread, 2);
    thread t3(workerThread, 3);
    thread t4(workerThread, 4);
    thread t5(workerThread, 5);

    Sleep(250);
    flag = 0;
    t1.join();
    t2.join();
    t3.join();
    t4.join();
    t5.join();
    return 0;
}
  • 0
    это очень специфичный для ОС ответ, и критическая секция на самом деле не о потоке (даже если поток обычно приводит к параллелизму)
  • 0
    Было бы полезно, если бы вы добавили описание, чтобы объяснить, как этот код отвечает на вопрос.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню