识别一个线程

时间:2018-03-22 08:31:53

标签: c++ multithreading

要识别线程,我们必须执行以下操作:
1)获取并保存其ID 2)在线程中运行的函数内,再次获取线程的id并将其与保存的id进行比较。

例如:http://coliru.stacked-crooked.com/a/8f608dff835f96d0
(该计划来自Josuttis的书“The C ++ Standard Library”,第2版。)

thread::id master_tid {};

/// declarations
void doSomething();


int main()  
{
   thread master {doSomething};
   master_tid = master.get_id();

   thread slave {doSomething};

   /// ...

   /// join with threads
   master.join();
   slave.join();

   cout << "done" << endl;
}


void doSomething()
{
   if (this_thread::get_id() == master_tid)
      cout << "master thread ..."
           << endl;
   else
      cout << "NOT master thread ..."
           << endl;

   /// ...
}

输出结果为:

master thread ...
NOT master thread ...
done

但是,只有在调用doSomething()函数和保存主线程的id之间没有延迟时,上述方案才有效。

如果引入了这样的延迟,doSomething()函数将无法区分主线程和任何其他线程,因为,当它运行时,主线程的id还没有 已保存在引用变量中。
例如:http://coliru.stacked-crooked.com/a/0bff325f872ba9c2

thread::id master_tid {};

/// declarations
void doSomething();


int main()  
{
   thread master {doSomething};
   thread slave {doSomething};

   /// delay
   this_thread::sleep_for(seconds {1});

   master_tid = master.get_id();

   /// ...

   /// join with threads
   master.join();
   slave.join();

   cout << "done" << endl;
}


void doSomething()
{
   /// ...
}

现在,由于延迟,输出如下:

NOT master thread ...
NOT master thread ...
done

因此,我想问一下,我们怎样才能使这个方案完美运作?我们是否需要使用条件变量在主线程和其他线程之间进行通信,以指示是否已保存线程ID?

或者,有一些更简单的方法吗?

5 个答案:

答案 0 :(得分:3)

所有线程都必须等到master_tid被分配。您应该使用同步机制,而不是手动sleep_for,它容易出错并最终导致程序中出现错误。在您的情况下,您希望所有线程都等待条件,您可以使用条件变量。 However, I would just pass different functions to master and slave, or pass a parameter.

#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex m;
std::condition_variable cv;
thread::id master_tid {};
bool ready = false;

/// declarations
void doSomething() {
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, []{return ready;});

    // master_tid is now assigned
   if (this_thread::get_id() == master_tid)
      cout << "master thread ..."
           << endl;
   else
      cout << "NOT master thread ..."
           << endl;
}


int main()  
{
   thread master {doSomething};

   thread slave {doSomething};

    {
        std::lock_guard<std::mutex> lk(m);
        ready = true;
        master_tid = master.get_id();
    }
    cv.notify_all();

   /// ...

   /// join with threads
   master.join();
   slave.join();

   cout << "done" << endl;
}

答案 1 :(得分:1)

使用std::future可以轻松解决此问题。

示例:

#include <future>
#include <thread>
#include <functional>
#include <iostream>

/// declarations
void doSomething(std::shared_future<std::thread::id> future_master_thread);


int main()  
{
    std::promise<std::thread::id> promise_master_thread;
    auto shared_master_thread = promise_master_thread.get_future().share();
    std::thread master {std::bind(doSomething, shared_master_thread)};
    promise_master_thread.set_value(master.get_id());

    std::thread slave {std::bind(doSomething, shared_master_thread)};

   /// ...

   /// join with threads
   master.join();
   slave.join();

   std::cout << "done" << std::endl;
}


void doSomething(std::shared_future<std::thread::id> future_master_thread)
{
   if (std::this_thread::get_id() == future_master_thread.get())
      std::cout << "master thread ..."
           << std::endl;
   else
      std::cout << "NOT master thread ..."
           << std::endl;

   /// ...
}

答案 2 :(得分:0)

我不确定我是否完全理解了这个问题,但是不能将执行的函数传递给另一个参数来定义它是否是主线程?

void doSomething(bool isMaster) {
    if (isMaster)
      cout << "master thread ..."
           << endl;
   else
      cout << "NOT master thread ..."
           << endl;
}

std::thread master = std::thread(doSomething, true);
std::thread slave = std::thread(doSomething, false);

我个人会将doSomething分成一般部分和一个特定部分,然后为master和slave创建特殊函数或者在lambda中定义它。

std::thread master = std::thread([]() {
    doMasterStuff();
    doSomething();
});

std::thread slave([]() {
    doSlaveStuff();
    doSomething();
});

或者我会使用模板方法模式

class ThreadFunction {
private:
    void doSpecific() = 0;
    void doSomething() { ... }
public:
    void operator()() {
        doSpecific();
        doSomething();
     }
};

class MasterThread: public ThreadFunc {
     void doSpecific() {
          cout << "master thread ..."
               << endl;
     }
};

或者创建一个类,将特定部分作为&#34;策略&#34;。

template<typename T>
class ThreadFunc2 {
private:
    T specific;
    void doSomething() { ... };
public:
    ThreadFunc2(T s): specific( std::move(s) ) {}
    void operator()() {
        specific();
        doSomething();
    }
};

std::thread master([]() {          
    cout << "master thread ..." << endl;
});

答案 3 :(得分:0)

实际上你的问题是你创建了2个线程并将它们的id与无初始值进行比较。

确实我们看一下调度

--------------------------------------------> main time 
     |       |        |          | 
   master  slave     sleep      attribute id
--------------------------------------------> master time 
        |
      do_something
--------------------------------------------> slave time
                |
             do_something

让他们能够看到他们是主人还是拯救他人的一种方法是使用一个告诉主人或者药膏已被识别的bool。

int main()  
{
   bool know_master = false;
   thread master {doSomething};
   thread slave {doSomething};

   /// delay
   this_thread::sleep_for(seconds {1});

   master_tid = master.get_id();
   know_master = true;

   /// ...

   /// join with threads
   master.join();
   slave.join();

   cout << "done" << endl;
}


void doSomething()
{
   while (! know_master) {
        //sleep here
   }
   if (this_thread::get_id() == master_tid)
      cout << "master thread ..."
           << endl;
   else
      cout << "NOT master thread ..."
           << endl;

   /// ...
}

答案 4 :(得分:0)

在Linux上识别线程

除了其他答案之外,在Linux(特别是)上,您可以使用第一个pthread_setname_np(3)(在线程函数的开头附近)和pthread_getname_np之后识别线程。您还可以使用gettid(2)系统调用(返回一些唯一的整数)获得唯一的tid。

pthread_getname_np的缺点是你必须先调用pthread_setname_np一次(对于你自己明确创建的线程,它很容易;对于某些库创建的线程,它更难)。

gettid的缺点是它没有被C库包装。但是,这种包装对代码来说是微不足道的:

static inline pid_t mygettid(void) { return syscall(SYS_gettid, 0L); }

您需要syscall(2)<sys/syscall.h>

pthread_getname_npgettid都可能是特定于Linux的,但它们可用于唯一标识您的主题。

关于线程的一般提示

根据经验,您最好在创建线程时传递一些线程唯一数据,例如到pthread_create(3)std::thread构造函数的显式(第二个和更多)参数,特别是如果你想在你的线程函数中使用pthread_setname_np(在大多数其他情况下)。

因此,您将声明void doSomething(int);并使用

构建线程
 thread master {doSomething,10};
 thread slave {doSomething,42};

10和42的选择是任意的,你可能会声明像void doSomething(std::string)之类的东西然后有thread master {doSomething, std::string{"masterth"}};等......