C++ 如何在不让用户等待的情况下管理多个线程?
对不起,如果这句话用得不好,我不知道如何准确地描述我想要的标题。但基本上我的目标是让用户输入时间,让程序在时间过去时提醒他们。时间过后,程序会寻找另一个时间,同时允许用户输入更多的时间。基本上,它看起来是这样的:C++ 如何在不让用户等待的情况下管理多个线程?,c++,multithreading,C++,Multithreading,对不起,如果这句话用得不好,我不知道如何准确地描述我想要的标题。但基本上我的目标是让用户输入时间,让程序在时间过去时提醒他们。时间过后,程序会寻找另一个时间,同时允许用户输入更多的时间。基本上,它看起来是这样的: void printTime(tm time) { //sleep until time cout << "it is " << time << endl; lookForNextTime(); } void lookFor
void printTime(tm time) {
//sleep until time
cout << "it is " << time << endl;
lookForNextTime();
}
void lookForNextTime() {
//find earliest time
printTime(time);
}
int main() {
//create thread in lookForNextTime
while(true) {
//ask user to insert more times until they quit
}
}
void打印时间(tm时间){
//晚睡
Cuth欢迎使用StActPox.C++中我对线程的处理是相当新的,所以我不熟悉最好的库和技术,但我可以至少分享一些我所知道的基础知识,希望这能让你感觉从哪里去。
如果我理解正确,我相信你们的问题主要围绕着
join()
展开
调用join()
是在继续之前等待线程加入的方式,但您不必在创建线程后立即这样做,否则它将毫无意义。您可以让线程以自己的方式运行,当它完成时,它将结束,而无需来自主线程的任何进一步输入(请纠正我,我错了)
关于join()
的重要一点是,在退出程序之前,您对所有线程调用它以等待它们(或者以某种方式安全地中止它们)。否则,即使在main()之后,它们也会继续运行返回并将在尝试访问内存时引发问题,因为它们不再连接到正在运行的进程。另一种可能的用途是在计算中让几个工作线程在某些检查点匹配,以便在获取下一个工作块之前共享结果
希望这能有所帮助。不过我还有一些想法,我想我会与大家分享,以防您或未来的读者不熟悉本示例中涉及的其他一些概念
您没有指出是否有一种方法可以跟踪时间并在线程之间共享时间,因此我只想给出一个快速提示:
在添加或弹出缓冲区之前锁定缓冲区。
这样做很重要,以避免争用情况,即一个线程可能试图弹出某些内容,而另一个线程正在添加并导致出现奇怪的问题,特别是如果您最终使用了诸如which排序之类的内容,并确保插入时任何给定元素只有一个副本
如果你不熟悉锁定机制,那么你可以在C++中找到使用互斥和信号量的例子,或者搜索“锁定”或“同步对象”。
就实际创建线程而言,我想到了两件事。一个想法是使用线程池。有几个库用于处理线程池,其中一个例子就是苹果的开源(通常称为libdispatch)它可以在Linux上使用,但对于Windows,您可能需要查找其他内容(不幸的是,我对Windows平台不太熟悉)。他们管理您正在使用和未使用的线程的生命周期,因此他们可能会提供帮助。再次,我本人对此有点陌生,我不能100%确定这对您来说是最好的事情,特别是因为您还有项目的其他部分要解决,但这可能值得一看
即使不使用线程池(比如说你使用pthreads),我也不认为你需要太担心自己启动一堆线程,只要你对它进行一些合理的限制(多少是合理的,我不确定,但如果您查看macOS中的Activity Monitor或Windows中的Task Manager或Linux中的TOP,您会发现在任何给定的时间,您机器上的许多程序可能正在运行相当多的线程,现在我有5090个线程正在运行,327个进程。这大约是每个进程15.5个线程。有些进程运行得很高呃)
希望有帮助。
欢迎StAcdPosiv.I是一个新的C++线程,所以我不熟悉最好的库和技术,但我可以至少分享一些我所知道的基础知识,希望这能让你感觉从哪里去。
如果我理解正确,我相信你们的问题主要围绕着
join()
展开
调用join()
是在继续之前等待线程加入的方式,但您不必在创建线程后立即这样做,否则它将毫无意义。您可以让线程以自己的方式运行,当它完成时,它将结束,而无需来自主线程的任何进一步输入(请纠正我,我错了)
关于join()
的重要一点是,在退出程序之前,您对所有线程调用它以等待它们(或者以某种方式安全地中止它们)。否则,即使在main()之后,它们也会继续运行返回并将在尝试访问内存时引发问题,因为它们不再连接到正在运行的进程。另一种可能的用途是在计算中让几个工作线程在某些检查点匹配,以便在获取下一个工作块之前共享结果
希望这能有所帮助。不过我还有一些想法,我想我会与大家分享,以防您或未来的读者不熟悉本示例中涉及的其他一些概念
您没有指出是否有一种方法可以跟踪时间并在线程之间共享时间,因此我只想给出一个快速提示:
在添加或弹出缓冲区之前锁定缓冲区。
这样做很重要,以避免一个线程试图弹出某些内容,而另一个线程正在添加并导致出现奇怪的问题,特别是如果您最终使用了诸如which sorts之类的内容并确保只有
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <condition_variable>
#include <mutex>
bool spuriousWakeup = true;
bool timerSet = false;
bool terminated = false;
int timerSeconds = 0;
std::thread timerThread;
std::mutex timerMutex;
std::condition_variable timerWakeup;
void printTimeThreadFunc()
{
// thread spends most of the time sleeping from condition variable
while (!terminated){
std::unique_lock<std::mutex> lock(timerMutex);
if(timerSet){
// use condition variable to sleep for time, or wake up if new time is needed
if(timerWakeup.wait_for(lock, std::chrono::seconds(timerSeconds), []{return !spuriousWakeup;})){
std::cout << "setting new timer for " << timerSeconds << " seconds!" << std::endl;
}
else{
std::cout << "timer expired!" << std::endl;
// timer expired and there is no time to wait for
// so next time through we want to get the un-timed wait
// to wait indefinitely for a new time
timerSet = false;
}
}
else{
std::cout << "waiting for timer to be set!" << std::endl;
timerWakeup.wait(lock, []{return !spuriousWakeup;});
}
spuriousWakeup = true;
}
}
int main()
{
// timer thread will exist during program execution, and will
// be communicated with through mutex, condition variable, and flags.
timerThread = std::thread(printTimeThreadFunc);
while (!terminated){
// get input from user
std::string line;
std::getline(std::cin, line);
// provide a way to quit
if (line == "end") {
terminated = true;
break;
}
// make sure its a number
try{
// put scope on lock while we update variables
{
std::unique_lock<std::mutex> lock(timerMutex);
timerSet = true;
timerSeconds = std::stoi(line);
spuriousWakeup = false;
}
// let thread know to process new time
timerWakeup.notify_one();
}
catch (const std::invalid_argument& ia) {
std::cerr << "Not a integer" << ia.what() << '\n';
}
}
// clean up thread
if(terminated && timerThread.joinable()){
timerWakeup.notify_one();
timerThread.join();
}
}