在cpp中从父线程暂停和恢复线程

Pause and resume thread from parent thread in cpp

本文关键字:线程 暂停 恢复 cpp      更新时间:2023-10-16

我正在使用cpp线程库。我有一个父线程T1,它有一个子线程T2。T2只会循环一些项,做一些处理。我需要从T1使用函数调用暂停和恢复T2。T1和T2属于同一类。我需要它在特定事件达到T1时停止处理数据;请不要推荐任何其他线程实现库。

    C::t2_func{
      for(int i=0;i<data.size();i++)
        process_data(data[i]);
    }
    C::spawn(){
       t2 = std::make_unique<std::thread>(std::bind(&C::t2_func, this));
    }
    C::pause(){
         //pause t2
    }
    C::resume(){
         //resume t2
    }

虽然不可能完全在线程外部暂停STL线程(某些具有更广泛线程管理功能的平台特定线程可能支持它),但是可以在线程的配合下暂停线程。请注意,这意味着暂停不会在线程执行期间的任意点发生,而只会在线程函数支持暂停的特定点发生。

暂停线程的核心非常简单:一个指示是运行还是暂停的标志。访问共享的线程数据,比如标志,必须是同步的;这是第二个方面,它必然使实现更加复杂,尽管不是非常复杂。

同步是通过锁(如lock_guardunique_lock)在互斥锁上实现的;互斥锁确保代码的关键部分是互斥的(即不会被另一个中断),锁负责管理锁和解锁互斥锁。

另外,使用一个条件变量来表示线程应该运行:暂停线程等待,直到标志表示"运行",而恢复函数通知标志为"运行"。由于条件变量访问共享数据,所以它也使用互斥锁。std::condition_variable支持两种等待方式:一种只是等待通知,但可能会遭受虚假唤醒,另一种需要一个可调用的谓词,并将等待通知和谓词返回true(允许虚假唤醒被忽略)。一般来说,后者是你想要的。

假设线程函数有空返回值,一个示例实现可以是:

// shared data, threading primitives
bool pause = false;
std::condition_variable cv;
std::mutex m;
// T2's main thread function
void C::t2_func() {
  for(int i = 0; i < data.size(); i++){
    // wait until unpause is signaled
    nap();
    
    // do some work
    process_data(data[i]);
  }
}
void C::spawn() {
   t2 = std::make_unique<std::thread>(std::bind(&C::t2_func, this));
}
// thread management
void C::nap() {
    // must use a `unique_lock` with a `condition_variable`, not a `lock_guard`
    std::unique_lock<decltype(m)> lk(m);
    cv.wait(lk, []{ return ! pause; });
}
void C::pause() {
     //pause
     std::lock_guard<decltype(m)> lk(m);
     pause = true;
}
void C::resume() {
     std::lock_guard<decltype(m)> lk(m);
     pause = false;
     cv.notify_one();
     //resume t2
}

不能在外部暂停线程。但是线程可以暂停自己。考虑使用std::condition_variable和布尔标志is_paused。然后在你的工作线程中,每次迭代你锁定一个互斥锁,检查线程是否应该暂停,如果应该,等待条件变量直到is_paused重置为false。在主线程中锁定互斥锁,更改is_paused并通知条件变量。

许多人在论坛上询问是否可以暂停、恢复或取消一个线程,不幸的是,目前我们不能。但如果有迫切需要,我有时会这样做。让你的函数增量(细粒度),这样它就可以在一个循环中连续执行,你可以像下面的一个简单的例子所示:

void main()
{
enum tribool { False,True,Undetermine};
bool running = true;
bool pause = false;
std::function<tribool(int)> func = [=](long n)
  {
    long i;
    if (n < 2) return False;
    else
    if (n == 2) return True;
    for (i = 2; i < n; i++)
    {
        while (pause)
        {
            if (!pause) break;
            if (!running) return Undetermine;
        }
        if (n%i == 0) return False;
    }
    return True;
   };
    std::future<tribool> fu = std::async(func,11);
    pause = true; //testing pause
    pause = false;
   auto result = fu.get();
   if (result == True) std::cout << " Prime";
   else
   if (result == False) std::cout << " Not Prime";
   else
    std::cout << " Interrupted by user";
   return ;
 }