1

I have a collection of std::thread::id, and I would like to know if the related std::thread has finished, for any of the std::thread::id in the collection.

Is it possible?

canellas
  • 491
  • 5
  • 17
  • 2
    Possible duplicate of [How to check if a std::thread is still running?](https://stackoverflow.com/questions/9094422/how-to-check-if-a-stdthread-is-still-running) – Silvio Mayolo Dec 04 '17 at 01:16
  • I'm not sure if there is anything in `std::thread` that does what you are asking, but you could make all of your threads run in a wrapper function, and at the end of the wrapper function you add the thread id to some data structure, then check that data structure to see if a thread has finished. – Gary Holiday Dec 04 '17 at 01:17
  • 1) use a value as a mark of finish; 2) use std::async std::future std::promise rather than std::thread unless you have a very strong reason. – Yves Dec 04 '17 at 02:55
  • I do not have access to the thread, only to the thread id. Here is what I intend to do: https://pastebin.com/40CQxiNf Thanks for your time! – canellas Dec 05 '17 at 01:06
  • This is probably an XY question. Why do you care whether the thread has finished or not? Are you sure you don't really care whether some particular task is finished? – David Schwartz Dec 06 '17 at 02:40

2 Answers2

1

Not in a portable fashion. Generally you will have to have the threads set a flag to indicate the actual condition you want to test.

Zalman Stern
  • 3,161
  • 12
  • 18
0

I think I found out how:

struct logger {
enum level : int16_t { debug = 0, info = 1, warn = 2, error = 3, fatal = 4 };

~logger() {
    write_all();
}

logger & operator()(level p_level) {
    add(true)
            << "[" << get_level(p_level) << "]"
            << "[" << std::time(NULL) << "]"
            << "[" << std::this_thread::get_id() << "] ";
    return *this;
}

template <typename T>
logger & operator << (const T & p_val) {
    add() << p_val;
    return *this;
}
private:

struct at_thread_end {
  at_thread_end (std::function<void (std::thread::id)> p_callback
                 , std::thread::id p_id)
      : m_callback(p_callback)
      , m_id(p_id){}

  at_thread_end(at_thread_end && p_at_thread_end)
      : m_callback(std::move(p_at_thread_end.m_callback))
      , m_id(std::move(p_at_thread_end.m_id)) {}

  at_thread_end & operator=(at_thread_end && p_at_thread_end) {
      m_callback = std::move(p_at_thread_end.m_callback);
      m_id = std::move(p_at_thread_end.m_id);
      return *this;
  }

  ~at_thread_end() {
      m_callback(m_id);
  }

private:
  std::function<void (std::thread::id)> m_callback;
  std::thread::id m_id;
};

typedef std::map<std::thread::id, std::stringstream> streams;

void on_thread_end(std::thread::id p_id) {
    std::cout << "thread " << p_id << " ended" << std::endl;
    streams::iterator _ite = m_streams.find(p_id);
    if (_ite != m_streams.end()) {
        write(_ite->second.str());
        std::lock_guard<std::mutex> _lock(m_mutex_streams);
        m_streams.erase(_ite);
    }
}

std::stringstream & add(bool p_clean = false) {
    std::thread::id _id  = std::this_thread::get_id();
    streams::iterator _ite = m_streams.find(_id);
    if (_ite != m_streams.end()) {
        if (p_clean) {
            write(_ite->second.str());
            _ite->second.str("");
        }
        return _ite->second;
    }


    using std::placeholders::_1;
    thread_local at_thread_end
            _at_thread_end(std::bind(&logger::on_thread_end, this, _1)
                           ,_id);

    std::lock_guard<std::mutex> _lock(m_mutex_streams);
    m_streams[_id] = std::stringstream();
    return m_streams[_id];
}

std::string get_level(level p_level) {
    switch (p_level) {
    case level::debug:
        return "DEB";
    case level::info:
        return "INF";
    case level::warn:
        return "WAR";
    case level::error:
        return "ERR";
    case level::fatal:
        return "FAT";
    }
    return "LEVEL UNKNOW";
}

void write(const std::string & p_str) {
    std::lock_guard<std::mutex> _lock(m_mutex_write);
    if (p_str.size()) {
        std::cout << p_str << std::endl;
    }
}

void write_all() {
    std::lock_guard<std::mutex> _lock(m_mutex_streams);
    streams::iterator _end = m_streams.end();
    for (streams::iterator _ite = m_streams.begin(); _ite != _end; ++_ite) {
        write(_ite->second.str());
    }
}

streams m_streams;
std::mutex m_mutex_streams;
std::mutex m_mutex_write;

};

You can look at a full example at https://pastebin.com/z2HrF70U

canellas
  • 491
  • 5
  • 17