Может ли кто-нибудь опубликовать простой пример запуска двух (объектно-ориентированных) потоков на C++.
Я ищу реальные объекты потоков C++, которые я могу расширить для методов запуска (или что-то подобное), а не вызывать библиотеку потоков в стиле C.
Я пропустил любые запросы, специфичные для ОС, в надежде, что тот, кто ответит, ответит с использованием кроссплатформенных библиотек. Я сейчас просто разъясняю это.





Это во многом зависит от библиотеки, которую вы решите использовать. Например, если вы используете библиотеку wxWidgets, создание потока будет выглядеть так:
class RThread : public wxThread {
public:
RThread()
: wxThread(wxTHREAD_JOINABLE){
}
private:
RThread(const RThread ©);
public:
void *Entry(void){
//Do...
return 0;
}
};
wxThread *CreateThread() {
//Create thread
wxThread *_hThread = new RThread();
//Start thread
_hThread->Create();
_hThread->Run();
return _hThread;
}
Если ваш основной поток вызывает метод CreateThread, вы создадите новый поток, который начнет выполнение кода в вашем методе «Entry». В большинстве случаев вам нужно будет сохранить ссылку на поток, чтобы присоединиться к нему или остановить его. Подробнее здесь: документация wxThread
Вы забыли удалить ветку. Возможно, вы хотели создать ветку отстраненный?
Да, верно, я извлек код из некоторого кода, над которым сейчас работаю, и, конечно же, где-то хранится ссылка на поток, чтобы впоследствии присоединиться, остановить и удалить его. Спасибо. :)
Что ж, технически любой такой объект будет построен на основе библиотеки потоков в стиле C, потому что C++ только что указал стандартную модель std::thread в C++ 0x, которая была только что прибита и еще не реализована. Проблема носит в некоторой степени системный характер, технически существующая модель памяти C++ недостаточно строгая, чтобы обеспечить четко определенную семантику для всех случаев, когда «произошло раньше». Некоторое время назад Ханс Бём написал статью по этой теме и сыграл важную роль в разработке стандарта C++ 0x по этой теме.
http://www.hpl.hp.com/techreports/2004/HPL-2004-209.html
Тем не менее, существует несколько библиотек C++ для кросс-платформенных потоков, которые отлично работают на практике. Строительные блоки Intel thread содержат объект tbb :: thread, который близко приближается к стандарту C++ 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;
}
Поток ускорения - это здорово - моя единственная проблема заключалась в том, что вы не могли (когда я последний раз его использовал) фактически получить доступ к собственному базовому дескриптору потока, поскольку он был частным членом класса! В win32 есть ТОННА вещей, для которых вам нужен дескриптор потока, поэтому мы изменили его, чтобы сделать дескриптор общедоступным.
Другая проблема с boost :: thread заключается в том, что, насколько я помню, у вас нет свободы устанавливать размер стека нового потока - функция, которая, к сожалению, не включена в стандарт C++ 0x.
Этот код дает мне исключение boost :: noncopyable для этой строки: thread thread_1 = thread (task1); Может это потому, что я использую более старую версию (1.32).
task1 не был объявлен в этой области?
Создайте функцию, которую вы хотите, чтобы поток выполнялся, например:
void task1(std::string msg)
{
std::cout << "task1 says: " << msg;
}
Теперь создайте объект thread, который в конечном итоге вызовет указанную выше функцию следующим образом:
std::thread t1(task1, "Hello");
(Для доступа к классу #include <thread> необходим std::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 здесь
-std=c++0x -pthread.@ user2568508 Находясь в стандартной библиотеке, должно быть, да. Хотя вам воля необходимо приобрести компилятор с этой поддержкой.
@Ken: Я не уверен, что вы имеете в виду, приобретая компилятор с такой поддержкой ... У некоторых компиляторов его нет?
@ user2568508 Действительно. это функция C++ 0x (C++ 11). Я не думаю, что компилятор, поддерживающий все функции C++ 0x, еще существует, но у них есть частичная поддержка, и это общая функция для них.
Пожалуйста, помогите, там написано «невозможно открыть включаемый файл: 'поток': нет такого файла или каталога». Я использую VS10 на Win7.
@ Preza8 Я не пробовал этого с VS10, но можно ли добавить другие стандартные заголовки? Если да, проверьте, поддерживает ли это ваша версия MSVC++.
@ Preza8 VS10 не поддерживает многие функции C++ 11. VS12 и VS13 поддерживают резьбу.
В комментарии «Версии GCC ниже 4.7 используйте -std=c++0x (вместо -std=c++0x)» я считаю, что второй «C++ 0x» должен быть «C++ 11», но это невозможно изменить, потому что редактирование слишком мало.
@MasterMastic Какая разница, если вместо std :: thread t1 (task1, "Hello") мы используем std :: thread t1 (& task1, "Hello"), передавая ссылку на функцию? Должны ли мы в этом случае объявить функцию как указатель?
@ user2452253 Если вы передадите "task1", вы передадите указатель на функцию, которую хотите выполнить (что хорошо). Если вы передадите «& task1», вы передадите указатель на указатель функции, и результаты, вероятно, будут не такими красивыми и очень неопределенными (это было бы похоже на попытку выполнить случайные инструкции одну за другой. С большой вероятностью вы просто мог бы открываете ворота в ад). Вы действительно просто хотите передать указатель функции (указатель со значением адреса, с которого начинается функция). Если это не проясняет ситуацию, дайте мне знать и удачи!
Мне все еще нужен -pthread, чтобы скомпилировать его с 4.7.1, иначе программа не сможет работать с «завершением, вызванным после выброса экземпляра 'std :: system_error' what (): Operation not allowed».
Что мне делать, если я хочу, чтобы функция принимала поток, из которого она вызывается, в качестве параметра?
@ErikW В вызывающем потоке вы можете вызвать std::this_thread::get_id(), чтобы получить свой std::thread::id; тогда вы просто проходите его регулярно (то есть как я прошел string в ответе).
Я считаю, что есть опечатка, поток t1 (task1, "Привет"); должен быть поток t1 (& task1, "Привет");
@MasterMastic должен быть недействительным task1 ?? У меня есть функция, которая возвращает значение. Что я должен делать??
@MasterMastic "вы передаете указатель на указатель функции" Какой указатель на функцию?
@FatemehKarimi, извини, что ответил так поздно. Как правило, вы должны использовать конструкцию, отличную от потока, и я говорю конкретно о будущем / обещании. Я уверен, что вы можете найти множество реализаций, в том числе и в стандартной библиотеке. Если вам нужно более сложное решение, вы, вероятно, поищете подходящий (т. Е. Потокобезопасный) механизм или контейнер для передачи данных, например очередь.
@curiousguy Что ж, правильный способ сделать это - передать указатель на функцию, которую вы хотите запустить. В данном случае это функция task1. Таким образом, указатель на функцию также обозначается task1. Но спасибо, что подняли этот вопрос, потому что я считаю, что был неправ, и это эквивалентно &task1, поэтому не имеет значения, какую форму вы выберете для записи (если так, я предполагаю, что указатель на указатель функции - &&task1 - который будет Будь плохим). Соответствующий вопрос.
@MasterMastic Это будет and task1
Здесь можно добавить, что если вы не хотите использовать join в потоке, вы, вероятно, захотите detach - stackoverflow.com/questions/25559918/…
Также существует библиотека 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
#include <thread>
#include <iostream>
#include <vector>
using namespace std;
void doSomething(int id) {
cout << id << "\n";
}
/**
* Spawns n threads
*/
void spawnThreads(int n)
{
std::vector<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();
}
}
int main()
{
spawnThreads(10);
}
При поиске примера класса C++, который вызывает один из собственных методов экземпляра в новом потоке, возникает этот вопрос, но мы не смогли использовать ни один из этих ответов таким образом. Вот пример, который это делает:
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
}
}
Обратите внимание, что в этом примере не рассматривается мьютекс или блокировка.
Спасибо, что разместили это. Обратите внимание, что общая форма вызова потока для метода экземпляра выглядит примерно так: Foo f; std :: thread t (& Foo :: Run, & f, args ...); (где Foo - это класс, который имеет Run () в качестве функции-члена).
Спасибо, что разместили это. Я серьезно не понимаю, почему во всех примерах потоковой передачи используются глобальные функции.
Измените это на shared_from_this, если текущий класс является производным от enable_shared_from_this.
Если не требуется отдельная функция в глобальных пространствах имен, мы можем использовать лямбда-функции для создания потоков.
Одним из основных преимуществ создания потока с использованием лямбда является то, что нам не нужно передавать локальные параметры в качестве списка аргументов. Мы можем использовать список захвата для того же самого, и свойство закрытия лямбда позаботится о жизненном цикле.
Вот пример кода
int main() {
int localVariable = 100;
thread th { [=](){
cout<<"The Value of local variable => "<<localVariable<<endl;
}};
th.join();
return 0;
}
Безусловно, я обнаружил, что лямбда-выражения C++ - лучший способ создания потоков, особенно для более простых потоковых функций.