mercredi 10 juillet 2019

What goes wrong when passing a std::sub_match as argument to a std::thread?

I'm passing a std::sub_match as an argument to a std::thread (see my example code below). The thread function expects a const string reference. A sub_match can be converted to a string. So everything compiles fine.

But sometimes the function receives the wrong string. When I convert the sub_match to a string before passing it to the thread it works as expected. What is the difference?

I think this is a race condition as the original sub_match may not exist anymore when the thread executes. But I thought arguments to threads would be copied anyway. How can I find out which arguments are safe to pass to a thread and which not?

#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <regex>
#include <unistd.h>

class test_t {
  public:
    test_t(void) {}
    ~test_t(void) {}

    void start(void){
     //-------------------------------------------------
     // Do some memory allocation.
     // The error seems to appear faster with that.
     std::vector<std::string> vec;
     for(unsigned int i = 0; i < 1000; ++i) {
        vec.push_back("test_test_test");
     }
     //-------------------------------------------------

     std::string event = "operating";
     std::smatch match;
     std::regex expr("\\(operating\\)",
         std::regex_constants::icase | 
         std::regex_constants::basic);

     if(std::regex_match(event, match, expr)) {
        std::cout << "start thread" << std::endl;
        m_thread = std::thread(&test_t::thread_func, this, match[1]);              //NOK
//        m_thread = std::thread(&test_t::thread_func, this, match[1].str());        // OK
//        m_thread = std::thread(&test_t::thread_func, this, (std::string)match[1]); // OK
        m_thread.detach();
        std::cout << "thread started" << std::endl;
     }
    }

  private:
    std::thread m_thread;

    void thread_func(const std::string& string) {
     if(string != "operating") {
        std::cout << "ERROR: string: \"" << string << "\"" << std::endl;
        exit(EXIT_FAILURE);
     } else {
        std::cout << "string: \"" << string << "\"" << std::endl;
     }
    }
};

int main(int argc, char** argv) {
  test_t test;
  while(1) {
    test.start();
    usleep(100);
  }
  return 0;
}

Compiled with: g++ --std=c++11 -pthread -o test main.cpp
g++ --version: g++ (SUSE Linux) 4.8.5

Expected output:
...
start thread
thread started
string: "operating"
(repeat)

Actual output:
...
start thread
thread started
string: "operating"
ERROR: string: "test_test"

Aucun commentaire:

Enregistrer un commentaire