如何从父线程中提取 pthread 的任务 id(tid)

How to extract taskid(tid) of a pthread from the parent thread?

本文关键字:任务 id tid pthread 提取 线程      更新时间:2023-10-16

我正在使用std::thread来启动线程。另外,我需要 /proc/[pid]/tasks/[tid] 上可用的工作线程的统计信息。我需要 tid 才能监控线程统计信息。我想知道是否有办法从父线程中提取tid。我知道来自worker 的系统调用 gettid(( 返回其 id,但我想要来自主站而不是从属服务器的 threadId。有没有办法从 std::thread.get_tid(( 的thread_id gor 中提取tid

我相信可能有更好的方法可以做到这一点,请建议:)

更新:
如何获取 std::thread(( 的 Linux 线程 ID 这提供了一些关于从worker获取tid的信息,增加了线程启动的开销。例如,可以从启动器线程调用std::thread t = std::thread(&wrapper); t.get_id()。我正在/正在查看是否有一个以安全的方式从主/启动器线程做同样的事情。

所有线程都有一个唯一的 id:
std::thread::id this_id = std::this_thread::get_id();

您可以在程序启动时将其存储在变量中,并且可以从其他线程访问它。

我明白你说线的意思,但即使一个线生了另一个线,他们也是兄弟姐妹。

如果希望主线程能够获取每个工作线程的/proc路径,则可以将工作线程对象包装在一个类中,该类在启动实际线程时会创建一个 path 属性,主线程稍后可以获取该属性。

举个例子:

#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
// A base class for thread object wrappers
class abstract_thread {
public:
    abstract_thread() {}
    abstract_thread(const abstract_thread&) = delete;
    abstract_thread(abstract_thread&& rhs) :
        m_th(std::move(rhs.m_th)), m_terminated(rhs.m_terminated), m_cv{}, m_mtx{} {}
    abstract_thread& operator=(const abstract_thread&) = delete;
    abstract_thread& operator=(abstract_thread&& rhs) {
        terminate();
        join();
        m_th = std::move(rhs.m_th);
        m_terminated = rhs.m_terminated;
        return *this;
    }
    virtual ~abstract_thread() {
        // make sure we don't destroy a running thread object
        terminate();
        join();
    }
    virtual void start() {
        if(joinable())
            throw std::runtime_error("thread already running");
        else {
            std::unique_lock<std::mutex> lock(m_mtx);
            m_terminated = true;
            // start thread and wait for it to signal that setup has been done
            m_th = std::thread(&abstract_thread::proxy, this);
            m_cv.wait(lock, [this] { return m_terminated == false; });
        }
    }
    inline bool joinable() const { return m_th.joinable(); }
    inline void join() {
        if(joinable()) {
            m_th.join();
        }
    }
    inline void terminate() { m_terminated = true; }
    inline bool terminated() const { return m_terminated; }
protected:
    // override if thread specific setup needs to be done before start() returns
    virtual void setup_in_thread() {}
    // must be overridden in derived classes
    virtual void execute() = 0;
private:
    std::thread m_th{};
    bool m_terminated{};
    std::condition_variable m_cv{};
    std::mutex m_mtx{};
    void proxy() {
        {
            std::unique_lock<std::mutex> lock(m_mtx);
            setup_in_thread(); // call setup function
            m_terminated = false;
            m_cv.notify_one();
        }
        execute(); // run thread code
    }
};
// an abstract thread wrapper capable of returning its /proc path
class proc_path_thread : public abstract_thread {
public:
    // function to call from master to get the path
    const std::string& get_proc_path() const { return m_proc_path; }
protected:
    void setup_in_thread() override {
        m_proc_path =
            std::move(std::string("/proc/")) + std::to_string(syscall(SYS_gettid));
    }
private:
    std::string m_proc_path{};
};
// two different thread wrapper classes. Just inherit proc_path_thread and implement
// "execute()". Loop until terminated() is true (or you're done with the work)
class AutoStartThread : public proc_path_thread {
public:
    AutoStartThread() { start(); }
private:
    void execute() override {
        while(!terminated()) {
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
            std::cout << std::this_thread::get_id() << " AutoStartThread runningn";
        }
    }
};
class ManualStartThread : public proc_path_thread {
    void execute() override {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        std::cout << std::this_thread::get_id() << " ManualStartThread runningn";
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
};
int main() {
    AutoStartThread a;
    std::cout << a.get_proc_path() << "t// AutoStartThread, will have pathn";
    ManualStartThread b;
    std::cout << b.get_proc_path()
              << "t// ManualStartThread not started, no pathn";
    b.start();
    std::cout << b.get_proc_path()
              << "t// ManualStartThread will now have a pathn";
    b.join();
    std::this_thread::sleep_for(std::chrono::milliseconds(1500));
    // terminate() + join() is called automatically when abstract_thread descendants
    // goes out of scope:
    //
    // a.terminate();
    // a.join();
}

可能的输出:

/proc/38207 // AutoStartThread, will have path
    // ManualStartThread not started, no path
/proc/38208 // ManualStartThread will now have a path
139642064209664 ManualStartThread running
139642072602368 AutoStartThread running
139642072602368 AutoStartThread running
139642072602368 AutoStartThread running
139642072602368 AutoStartThread running

您可以通过一个函数启动线程,该函数的第一个任务是向其发送 id 的消息,例如,经典地使用互斥体和 condvar:

#include <stdio.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <unistd.h>
struct tid_msg{
    pthread_mutex_t mx;
    pthread_cond_t cond;
    pid_t tid;
};
void *thr(void*A)
{
    struct tid_msg *msg = A;
    pid_t tid = syscall(SYS_gettid);
    pthread_mutex_lock(&msg->mx);
    msg->tid = tid;
    pthread_mutex_unlock(&msg->mx);
    pthread_cond_signal(&msg->cond);
    printf("my tid=%lun", (long unsigned)tid);
    return 0;
}
int main()
{
    struct tid_msg msg = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, -1 };
    pthread_t ptid;
    pthread_create(&ptid,0,thr,&msg);
    pthread_mutex_lock(&msg.mx);
    while(-1==msg.tid) pthread_cond_wait(&msg.cond,&msg.mx);
    pthread_mutex_unlock(&msg.mx);
    printf("their tid=%lun", (long unsigned)msg.tid);
    pthread_join(ptid,0);
}

或者只是通过一个原子变量(放松的内存排序在这里应该没问题,但您可以安全地使用它并使用顺序一致的默认值(:

#include <stdio.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdatomic.h>
void *thr(void*A)
{
    _Atomic pid_t *tidp = A;
    pid_t tid;
    tid = syscall(SYS_gettid);
    atomic_store_explicit(tidp, tid, memory_order_relaxed);
    printf("my tid=%lun", (long unsigned)tid);
    return 0;
}
int main()
{
    _Atomic pid_t tid=-1;
    pthread_t ptid;
    pthread_create(&ptid,0,thr,&tid);
    while(-1==atomic_load_explicit(&tid,memory_order_relaxed)) ;
    printf("their tid=%lun", (long unsigned)tid);
    pthread_join(ptid,0);
}