2015-10-29 3 views
0

Проблема появляется, когда в/из переменной из функции, вызываемой станд :: нить изменяет значение во время выполнения ...станд :: нить контекст выполнения (C++ 14)


Функция:

static int func(stThread_t *&pStThread) 

Параметры

pStThread: эпидермальный структура, которая имеет указатель на StD :: нить и другие переменные (некоторые флаги)

typedef struct stThread { 
    stThread() noexcept {...};  
    stThread(const stThread &cRigth) noexcept {...};  
    stThread & operator = (const stThread &cRigth) noexcept {...}; 

    std::thread *pThread; 
    volatile bool bBegin; 
    volatile bool bEnd; 

} stThread_t; 

Функция функ печати адрес станд :: Нить параметра pStThread и идентификатор потока

FUNC Перед 1785280 this_id 21968

после внесения this_thread :: сна в течение 2 секунд, распечатать его снова

функ АВЭС ... this_id 21968

static int func(stThread_t *&pStThread) { 

     std::thread::id this_id = std::this_thread::get_id(); 

     long long p_begin = (long long)pStThread; 
     std::cout << "func before " << std::to_string(p_begin) << " this_id " << this_id << "\n"; 
     std::cout.flush(); 

     pStThread->bBegin = true; 

     std::this_thread::sleep_for(std::chrono::milliseconds(2000)); 

     this_id = std::this_thread::get_id(); 
     long long p_end = (long long)pStThread; 
     std::cout << "func afer " << std::to_string(p_end) << " this_id " << this_id << "\n"; 
     std::cout.flush(); 

     pStThread->bEnd = true; 

     return 1; 
    }; 

В адрес указателя на StD :: нить подмигнули изменилась (corrutped, удален ..?)


pStThread pushing_back списка указателей struct stThread_t

std::list<stThread_t*> listOfThreads; 
listOfThreads.push_back(pStThread); 

Я читал о станд :: двигаться, но не работает с указателями


В конце есть поток «сборщик мусора», который он пытается стереть все темы, ожидающие выполнения.


Полный код здесь

#include <string> 
#include <list> 
#include <vector> 
#include <map> 
#include <thread> 
#include <mutex> 
#include <atomic> 

#include <iostream> 

typedef struct stThread { 
    stThread() noexcept { 
     pThread = NULL; 
     bBegin = false; 
     bEnd = false; 
    }; 

    stThread(const stThread &cRigth) noexcept { 
     this->pThread = cRigth.pThread; 
     this->bBegin = (bool)cRigth.bBegin; 
     this->bEnd = (bool)cRigth.bEnd; 
    }; 

    stThread & operator = (const stThread &cRigth) noexcept { 
     this->pThread = cRigth.pThread; 
     this->bBegin = (bool)cRigth.bBegin; 
     this->bEnd = (bool)cRigth.bEnd; 

     return *this; 
    }; 

    std::thread *pThread; 
    volatile bool bBegin; 
    volatile bool bEnd; 

} stThread_t; 

class CMain 
{ 
public: 
    typedef std::list<stThread_t*> MyList_threads; 
    MyList_threads listOfThreads; 

public: 
    CMain() { 

     std::cout << std::boolalpha << "Ex1 is move-constructible? " 
     << std::is_move_constructible<stThread_t>::value << '\n' 
     << "Ex1 is trivially move-constructible? " 
     << std::is_trivially_move_constructible<stThread_t>::value << '\n' 
     << "Ex1 is nothrow move-constructible? " 
     << std::is_nothrow_move_constructible<stThread_t>::value << '\n' 
     << "Ex2 is trivially move-constructible? " 
     << std::is_trivially_move_constructible<stThread_t>::value << '\n' 
     << "Ex2 is nothrow move-constructible? " 
     << std::is_nothrow_move_constructible<stThread_t>::value << '\n'; 
    }; 

    static int func(stThread_t *&pStThread) { 

     std::thread::id this_id = std::this_thread::get_id(); 

     long long p_begin = (long long)pStThread; 
     std::cout << "func before " << std::to_string(p_begin) << " this_id " << this_id << "\n"; 
     std::cout.flush(); 

     pStThread->bBegin = true; 

     std::this_thread::sleep_for(std::chrono::milliseconds(2000)); 

     this_id = std::this_thread::get_id(); 
     long long p_end = (long long)pStThread; 
     std::cout << "func afer " << std::to_string(p_end) << " this_id " << this_id << "\n"; 
     std::cout.flush(); 

     pStThread->bEnd = true; 

     return 1; 
    }; 

    int _createThreads() { 
     for (int iIdx = 0; (iIdx < 5); iIdx++) { 
     stThread_t *pStThread = new stThread_t; 

     pStThread->pThread = new std::thread(&CMain::func, 
      std::ref(pStThread)); 

     if (pStThread) { 
      do { 
       std::this_thread::sleep_for(std::chrono::milliseconds(100)); 
      } while (!pStThread->bBegin); 
      listOfThreads.push_back(pStThread); 

      std::string sLog; 
      sLog = "\nlistOfThreads.push_back " + std::to_string((long long)pStThread) + "\n"; 
      std::cout << sLog; 
      std::cout.flush(); 
     } 

     std::this_thread::sleep_for(std::chrono::milliseconds(1)); 
     } 
     return 1; 
    }; 

    int _main() { 

     _createThreads(); 

     std::thread thread_collector([=]() { 
     bool bEnd = false; 
     MyList_threads::iterator it; 
     it = listOfThreads.end(); 

     do { 
      stThread_t *pStThread = NULL; 

      if (it == listOfThreads.end()) { 
       it = listOfThreads.begin(); 
       if (it == listOfThreads.end()) bEnd = true; 
      } 
      else it++; 

      if (it != listOfThreads.end()) { 
       if ((*it)->bEnd) { 
        pStThread = *it; 

        listOfThreads.erase(it); 
        it = listOfThreads.begin(); 
       } 
      } 

      if (pStThread) { 
       if (pStThread->pThread) { 
        if (pStThread->pThread->joinable()) { 
        pStThread->pThread->join(); 

        std::cout << " element deleted " << std::to_string((long long)pStThread) << "\n"; 
        std::cout.flush(); 
        } 
        delete pStThread->pThread; 
        pStThread->pThread = NULL; 
       } 
       delete pStThread; 
      } 
      pStThread = NULL; 


      std::this_thread::sleep_for(std::chrono::milliseconds(1)); 

     } while (!bEnd); 
     }); 



     if (thread_collector.joinable()) { 
     thread_collector.join(); 
     } 

     return 1; 
    }; 
}; 

int main() 
{ 
    CMain _main; 
    _main._main(); 

    return 0; 
} 
+0

Было бы здорово, если бы вы могли сократить код и указать проблемные области. – SergeyA

+0

'volatile bool' не является потокобезопасным; вы хотите 'std :: atomic_bool', aka' std :: atomic '. – Hurkyl

+0

Если вы используете std :: thread, вы можете использовать ThreadSanitizer с последним clang и gcc – fghj

ответ

2

У вас есть довольно просто ошибка, которая в основном связана с потоками:

(1) func принимает ссылку на stThread_t*.

static int func(stThread_t *&pStThread); 

(2) Вы передать ссылку на pStThread

std::thread(&CMain::func,std::ref(pStThread)); 

(3) Что является локальной переменной, время жизни которых заканчивается, как только итерация закончена

for (int iIdx = 0; (iIdx < 5); iIdx++) { 
    stThread_t *pStThread = new stThread_t; 
    //... 
    } 

(4) И, следовательно, вы получаете неопределенное поведение, когда ваша функция пытается получить доступ к объекту после его уничтожения. (! Будьте осторожны здесь, «объект» относится к указателя в вопросе, а не объект указатель указывает на)

Неясно, почему вы настаиваете на прохождение pStThread ссылки; ваша функция фактически не изменяет указатель (только то, на что указывает), и вы, похоже, не намерены делать какие-либо вещи, на которые это устройство действительно хорошо.

+0

(2) Если я изменюсь для этого 'pStThread-> pThread = new std :: thread (& CMain :: func, // std :: ref (pStThread) pStThread); 'компилятор говорит: ' 1> D: \ Archivos de programa (x86) \ Microsoft Visual Studio 14.0 \ VC \ include \ thr/xthread (238): ошибка C2893: не удалось настроить шаблон функции «неизвестный тип std :: invoke (_Callable &&, _ Types && ...) '' – joseAndresGomezTovar

+0

Изменение' static int func (stThread_t * pStThread) {'work fine !! Спасибо! – joseAndresGomezTovar

+0

пытается проголосовать +1, я удаляю комментарии ... soz – joseAndresGomezTovar