2013-12-25 3 views
5

После использования потоков какое-то время я попал в ситуацию, когда мне нужен поток для запуска навсегда до тех пор, пока не будет вызвана функция (или любое событие). Для этого я создал значение bool для управления циклом while внутри функции, которая была выполнена потоком, но я быстро заметил, что внешние переменные не обновляются после запуска потока, заставляя поток никогда не останавливаться, когда его запрашивали ,C++ Темы, имеющие доступ к переменным класса

Heres некоторые простой код, чтобы представить этот вопрос:

#include <cstdio> 
#include <thread> 
#include <chrono> 

class A { 
public: 
    A(); 

    void startThread(); 
    void endThread(); 
private: 
    void threadCall(); 
    bool active; 
}; 

int main() { 
    A threadThing; 
    threadThing.startThread(); 
    printf("[M] Thread Created\n"); 
    std::this_thread::sleep_for(std::chrono::seconds(5)); 
    threadThing.endThread(); 
    printf("[M] Thread Killed\n"); 
    std::this_thread::sleep_for(std::chrono::seconds(5)); 

    return 0; 
} 

A::A() { 
    active = false; 
} 

void A::startThread() { 
    active = true; 
    std::thread AThread(&A::threadCall, *this); 
    AThread.detach(); 
} 

void A::endThread() { 
    active = false; 
} 

void A::threadCall() { 
    printf("[T] Thread Started\n"); 
    while (active) { 
     std::this_thread::sleep_for(std::chrono::seconds(2)); 
    } 
    printf("[T] Thread Ended\n"); 
} 

Ожидаемый результат этого будет то, что основная функция запускает поток, поток говорит, что это началось, то 4 секунды спустя поток убит и нить говорит, что это закончилось, когда в действительности нить никогда не говорит, что она заканчивается. Есть ли способ разрешить потоку доступ к «активной» переменной или мой подход к этой проблеме неверен? (Боковое замечание, я попытался понять это самостоятельно, но только получил материал, похожий на локальное хранилище потоков, которое похоже на его хранение только внутри потоков, а не доступ к внешней стороне, но я мог ошибаться)

ответ

7

Проблема с конструктором std::thread, он копирует/перемещает по умолчанию.

std::thread AThread(&A::threadCall, *this); 

это копирует объект в новый поток, поэтому проверка active переменных в новом объекте не имеет никакого эффекта.

вы можете удалить *

std::thread AThread(&A::threadCall, this); 

вы передаете указатель на объект в новый поток, он будет вызывать как метод, как этот (*this).threadCall().

Редактировать: как говорится в комментариях, это не гарантия того, чтобы быть потокобезопасным, вам необходимо использовать std::atomic<bool>, чтобы быть в безопасности.

+0

Этот ответ сработал, и я собираюсь принять его, потому что он более прямой. – lemondrop

+1

Это решение действительно создает гонку данных на 'active' и приводит к неопределенному поведению. – bames53

+0

@ bames53 Я не вижу гонки, могу ли вы разработать? – yngccc

5

А, многопоточность.

Что вам нужно сделать, это передать указатель класса A в качестве аргумента вашей функции, которая является вашей нитью.

void A::startThread() 
{ 
    active = true; 
    std::thread AThread(threadCall, this); 
    AThread.detach(); 
} 
void A::threadCall(A *aClass) 
{ 
    printf("[T] Thread Started\n"); 
    while (aClass->active) 
    { 
     std::this_thread::sleep_for(std::chrono::seconds(2)); 
    } 
    printf("[T] Thread Ended\n"); 
} 
+0

Wow thanks, это сработало. Одно изменение заключается в том, что вызов потока должен быть 'AThread (& A :: threadCall, * this, this);', dunno why, просто что-то делать с тем, как его частная функция или что-то в этом роде. – lemondrop

+0

Это странно, для меня это не будет принято. Вы используете это в Linux? –

+0

Нет, Visual Studio premium 2013 на окнах 8. – lemondrop

Смежные вопросы