代码之家  ›  专栏  ›  技术社区  ›  uliwitness

在运行之前获取std::thread的thread:id?

  •  1
  • uliwitness  · 技术社区  · 8 年前

    我试图在C++ 11的顶部构建线程安全层。 std::thread 其中每个对象都被分配给所属线程,并且某些调用在错误的线程上使用时会引发硬错误。拥有的线程是唯一可以将对象传输到另一个线程的线程。

    我把一切都做好了, 我找不到线索 thread::id 在它真正运行之前。我需要把新线程的ID附加到对象上,然后再把它交出来。

    如果我用

    std::thread newThread( [theObject]()
                           {
                               // use theObject here.
                           } );
    

    我看到有一个默认的构造函数 std::线程

    有没有办法在线程上执行两步构造,或者在创建时控制线程的ID?

    4 回复  |  直到 8 年前
        1
  •  3
  •   seccpur    8 年前

    通过传递一个唯一的std::promise参数来启动每个未激活的线程,首先获取线程id(线程id用作按引用传递的参数),然后让它等待线程管理器设置承诺。这也将消除使用条件变量的麻烦。

    编辑 片段

    class smart_thread {
    public:
        smart_thread(std::function<void(void)> task)
        {
            thread_ = std::thread([=]() {
                id_ = std::this_thread::get_id();
                // wait here till activated
                future_.get();
                if(active_) task();
            });
        }
    
        void activate()  {
            promise_.set_value();
            active_ = true;
        }
    
        ~smart_thread() {
            if(!active_) promise_.set_value();
            thread_.join();
        }    
    private:
        std::thread::id id_;
        std::atomic<bool> active_ = false;
        std::thread thread_;
        std::promise<void> promise_;
        std::future<void> future_ = promise_.get_future();
    };
    
    void main()
    {
        auto task = []() { std::cout << "Hello World\n"; };
        smart_thread thread(task); // start thread inactive mode
        thread.activate(); // activate thread
    }
    
        2
  •  6
  •   templatetypedef    8 年前

    bool isReady = false;
    bool wasReceived = false;
    std::mutex mutex;
    std::condition_variable condition;
    
    std::thread newThread([theObject, &isReady, &mutex, &condition] {
       /* Wait until we've been cleared to go. */
       std::unique_lock<std::mutex> lock(isReady);
       condition.wait(lock, [&isReady] { return isReady; });
    
       /* Signal that we're done. */
       wasReceived = true;
       lock.unlock();
       condition.notify_one();
    
       /* Put code here to do whatever it is that the thread should do. */
    });
    
    /* Read the thread's ID. It's currently waiting for us. */
    auto id = newThread.get_id();
    
    /* Tell the thread that we're ready for it. */
    std::unique_lock<std::mutex> lock(mutex);
    isReady = true;
    condition.notify_one();
    
    /* Wait until the thread has confirmed that it's ready. */
    condition.wait(lock, [&] { return wasReceived; });
    

    这将创建线程,并让它坐着等待,直到创建者有机会读取它的ID。一旦发生这种情况,创建者然后等待,直到线程确认它已准备就绪,然后从那里您可以使用线程ID,无论您喜欢什么。

    小心上面代码中的错误-它完全未经测试。:-)

        3
  •  5
  •   Jerry Coffin    8 年前

    不——只要创建一个线程,它就开始运行。如果你想在它做任何事情之前得到它的ID,你可能需要创建一个小包装器,在这里你可以给线程(例如)传递一个CV和一个队列,在那里存放它的输出。

        4
  •  0
  •   dgnuff    8 年前

    是否可以创建一个模板类来接受 std::function<void(T *object)> . 如果需要传入其他参数,可以使用匿名闭包轻松完成此操作。

    template <class T>
    class ThreadWrapper
    {
    public:
        ThreadWrapper(std::function<void(T *object)> function, T *object) :
        {
            m_thread = std::thread(WrapFunction, function, object);
            //optionally
            m_thread.detach();
        }
        static void WrapFunction(ThreadWrapper *wrapper, std::function<void()> function, T *object)
        {
            // Get the thread id and save in the object
            object->SetThreadId(get_id());
            // Now actually invoke the thread routine, with the id already installed.
            function(object);
        }
    }
    
    // Cleanup is left as an exercise for the reader.