简体   繁体   English

通过写入外部变量来取消c ++线程是安全/有效的吗?

[英]Is it safe/efficient to cancel a c++ thread by writing to an outside variable?

I have a search problem, which I want to parallelize. 我有一个搜索问题,我想并行化。 If one thread has found a solution, I want all other threads to stop. 如果一个线程找到了解决方案,我希望所有其他线程都停止。 Otherwise, if all threads exit regularly, I know, that there is no solution. 否则,如果所有线程都定期退出,我知道,没有解决方案。

The following code (that demonstrates my cancelling strategy) seems to work, but I'm not sure, if it is safe and the most efficient variant: 以下代码(演示我的取消策略)似乎有效,但我不确定,如果它是安全且最有效的变体:

#include <iostream>
#include <thread>
#include <cstdint>
#include <chrono>

using namespace std;

struct action {
  uint64_t* ii;

  action(uint64_t *ii) : ii(ii) {};

  void operator()() {
    uint64_t k = 0;
    for(; k < *ii; ++k) {
      //do something useful
    }
    cout << "counted to " << k << " in 2 seconds" << endl;
  }
  void cancel() {
    *ii = 0;
  }
};


int main(int argc, char** argv) {
  uint64_t ii = 1000000000;
  action a{&ii};
  thread t(a);
  cout << "start sleeping" << endl;
  this_thread::sleep_for(chrono::milliseconds(2000));
  cout << "finished sleeping" << endl;
  a.cancel();
  cout << "cancelled" << endl;
  t.join();
  cout << "joined" << endl;
}

Can I be sure, that the value, to which ii points, always gets properly reloaded? 我可以肯定, ii指向的值总能正确重新加载吗? Is there a more efficient variant, that doesn't require the dereferenciation at every step? 是否有一个更有效的变体,不需要在每一步都进行去引用? I tried to make the upper bound of the loop a member variable, but since the constructor of thread copies the instance of action , I wouldn't have access to that member later. 我试图使循环的上限成为一个成员变量,但由于thread的构造函数复制了action的实例,我以后无法访问该成员。

Also: If my code is exception safe and does not do I/O (and I am sure, that my platform is Linux), is there a reason not to use pthread_cancel on the native thread? 另外:如果我的代码是异常安全的并且不执行I / O(我确信,我的平台是Linux),是否有理由不在本机线程上使用pthread_cancel

No, there's no guarantee that this will do anything sensible. 不,不能保证这会做任何明智的事情。 The code has one thread reading the value of ii and another thread writing to it, without any synchronization. 代码有一个线程读取ii的值,另一个线程写入它,没有任何同步。 The result is that the behavior of the program is undefined. 结果是程序的行为未定义。

I'd just add a flag to the class: 我只是在课堂上添加一个标志:

std::atomic<bool> time_to_stop;

The constructor of action should set that to false , and the cancel member function should set it to true . action的构造函数应该将其设置为false ,并且cancel成员函数应将其设置为true Then change the loop to look at that value: 然后更改循环以查看该值:

for(; !time_to_stop && k < *ii; ++k)

You might, instead, make ii atomic. 相反,你可以使ii原子化。 That would work, but it wouldn't be as clear as having a named member to look at. 这样可行,但它不会像有一个命名成员那样清楚。

First off there is no reason to make ii a pointer. 首先,没有理由让ii成为指针。 You can have it just as a plain uint64_t . 你可以像普通的uint64_t一样拥有它。

Secondly if you have multiple threads and at least one of them writes to a shared variable then you are going to have to have some sort of synchronization. 其次,如果你有多个线程,并且至少有一个线程写入共享变量,那么你将不得不进行某种同步。 In this case you could just use std::atomic<uint64_t> to get that synchronization. 在这种情况下,您可以使用std::atomic<uint64_t>来获得同步。 Otherwise you would have to use a mutex or some sort of memory fence. 否则你将不得不使用互斥锁或某种内存栅栏。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM