手机网站有什么区别吗深圳网站建设公司服务怎么做
web/
2025/9/29 14:40:30/
文章来源:
手机网站有什么区别吗,深圳网站建设公司服务怎么做,设计网页报价,石家庄经济join detachjoin和detach为最基本的用法#xff0c;join可以使主线程#xff08;main函数#xff09;等待子线程#xff08;自定义的function_1函数#xff09;完成后再退出程序#xff0c;而detach可以使子线程与主线程毫无关联的独立运行#xff0c;当主线程执行…join detachjoin和detach为最基本的用法join可以使主线程main函数等待子线程自定义的function_1函数完成后再退出程序而detach可以使子线程与主线程毫无关联的独立运行当主线程执行完毕后直接退出程序不管子线程是否执行完毕。#includeiostream
#includethread
using namespace std;// 子线程函数
void function_1()
{for(int i10;i0;i--) // 循环10次输出cout Hello endl;
}int main()
{thread t1(function_1);//线程开始//t1.join();//方式1结合等待其完成t1.detach();//方式2分离使其自行运行cout未来得及输出完毕主线程已结束cout ~~~~~~~~~~~World~~~~~~~~~~~ endl;if (t1.joinable()){t1.join();}return 0;
}
detach方法的执行结果如下可以看出子线程没来得及执行完毕。Hello
~~~~~~~~~~~World~~~~~~~~~~~
请按任意键继续. . .如果换成join方法则可以输出10条Hello语句。Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
~~~~~~~~~~~World~~~~~~~~~~~
请按任意键继续. . .try-catch异常捕获机制的使用join可以使某些比较重要的函数执行完毕后再退出但当程序出现异常时程序仍会直接退出join没有起到应有的作用这是可以通过try-catch异常捕获机制结合join方法使某些函数子线程在程序出现异常时也能先执行完毕再退出例子如下通过OpenCV读取显示一张不存在的图片产生异常。#includeiostream
#includethread
#includeopencv2/opencv.hpp// 子线程函数假定该函数比较重要无论如何都要执行完毕再退出程序
void function_1()
{for (int i 0; i 100; i){std::cout Hello i std::endl;}
}int main()
{std::thread t1(function_1);//t1线程开始运行try //【捕获异常的范围】{cv::Mat img cv::imread(1.jpg);//读取一张不存在的图片使下句的图片显示出现异常cv::imshow(, img);//此处将出现异常?错误?//出现异常会导致整个程序直接退出//捕获异常后可以进行补救如使t1子线程执行完毕。}catch (...)//捕获所有异常{std::cout catch............... std::endl;t1.join();//使子线程执行完毕throw;}t1.join();std::cout 主程序正常退出 std::endl;return 0;
}
可以看出运行后产生了一个OpenCV Error没能输出主程序正常退出 但子线程在程序出现异常后依然可以继续执行完毕。HelloOpenCV Error: Assertion failed (size.width0 size.height0) in cv::imshow, file D:Tools1opencvopencvsourcesmoduleshighguisrcwindow.cpp, line 325
0
Hello1catch...............Hello2
Hello3
Hello4
Hello5
此处省略...
Hello98
Hello99通过类构造子线程 ref方法传参C开发中更常使用类作为子线程函数而不是单独的某个函数。注意一点在线程按引用传递参数时的写法需要使用std::ref方法。#includeiostream
#includethread
#includestringclass Fctor
{
public:void operator()(std::string msg)//按【引用】传递参数{std::cout from t1: msg std::endl; msg Hello;//修改传入的参数用于后面的主线程输出}
};int main()
{std::string s -----------World-----------;//待传入的参数用于子线程输出// 方式1a这种方式会自动复制一份参数传进去//Fctor fct;//std::thread t1(fct,s);//t1线程开始运行// 方式1b这种方式会自动复制一份参数传进去//std::thread t1((Fctor()), s);//t1线程开始运行// 方式2a按引用传递Fctor fct;std::thread t1(fct, std::ref(s));//t1线程开始运行// 方式2b按引用传递//std::thread t1((Fctor()), std::ref(s));t1.join();std::cout from main: s std::endl;return 0;
}
运行结果方式1a或1bfrom t1:-----------World-----------
from main:-----------World-----------
请按任意键继续. . .方式2a或2b:from t1:-----------World-----------
from main:Hello
请按任意键继续. . .mov方法传参 线程对象移动除了使用ref方法对子线程进行传参还可以使用mov方法传参此外mov还可以移动线程对象。#includeiostream
#includethread
#includestringclass Fctor
{
public:void operator()(std::string msg)//按引用传递参数{std::cout from t1: msg std::endl;msg Hello;}
};int main()
{std::string s ----------------World---------------;std::cout Main_thread_ID: std::this_thread::get_id() std::endl;//主线程IDstd::thread t1((Fctor()), std::move(s));//子线程1(将字符串从主线程移动到子线程)std::cout Sub_thread1_ID t1.get_id() std::endl;//线程对象只能被移动不能被复制。std::thread t2 std::move(t1);//子线程2接管子线程1此时子线程1为空std::cout Sub_thread2_ID t2.get_id() std::endl;//可以看到两个子线程的ID是相同的t2.join();//等待子线程2结束//检测硬件并发特性(此句只是用来显示计算机支持的并发线程数量)std::cout std::thread::hardware_concurrency() std::endl;return 0;
}
运行结果如下可以看出传参无误并且两个子线程的ID相同说明子线程对象移动成功。Main_thread_ID:36576
from t1:Sub_thread1_ID37472----------------World---------------Sub_thread2_ID37472
8
请按任意键继续. . .mutex lock_guardmutex即互斥量可理解为一把锁访问某些资源时先加锁访问后解锁。 另一进程访问同一资源时首先尝试加锁如果锁处于未释放状态则无法加锁需等待其它线程对锁的释放。#includeiostream
#includethread
#includestring
#includemutexstd::mutex mu;//【互斥对象】》一把锁通过函数调用cout并为cout加锁防止同时访问cout
void share_print(std::string msg, int id)
{mu.lock();std::cout msg id std::endl;mu.unlock();
}//子线程函数
void function_1()
{for(int i 0; i 100; i)share_print(from t1: ,i );
}int main()//主线程
{std::thread t1(function_1);//t1线程开始运行for (int i 0; i 100; i){share_print(from main:, i);}t1.join();//等待子线程结束return 0;
}
运行结果类似如下from t1:0
from main:0
from t1:1
from main:1
from t1:2
from t1:3
from t1:4
from t1:5
省略...如果未使用加锁机制两线程会互相争抢cout的使用权从而导致输出混乱注释掉mu.lock()与mu.unlock()后的输出结果如下from t1:0from main:0from t1:1from main:1from t1:2from main:2from t1:3
from main:3from t1:4from t1:5from main:4
省略...由于lock()与unlock()必须成对出现为方便管理出现了lock_guard它可以对mutex进行管理自动实现lock()与unlock()原理是在其构造与析构中自动调用。另外还可有附加参数。修改上面的share_print为如下可实现同样的效果。void share_print(std::string msg, int id)
{std::lock_guardstd::mutex guard(mu);std::cout msg id std::endl;
}
下面的代码是将share_print封装到一个类中并添加将输出信息同时保存到文件中的功能#includeiostream
#includethread
#includestring
#includemutex
#includefstreamclass LofFile
{
public:LofFile(){ f.open(log.txt); }~LofFile(){ f.close(); }void shared_print(std::string id, int value){std::lock_guardstd::mutex locker(m_mutex);f from id : value std::endl;//写入文件std::cout from id : value std::endl;//输出}private://受保护的成员std::mutex m_mutex;//锁std::ofstream f;//此时f完全在锁的保护下
};void function_1(LofFile log)
{for (int i 0; i -100; i--)log.shared_print(t1, i);
}int main()//主线程
{LofFile log;std::thread t1(function_1,std::ref(log));//t1线程开始运行for (int i 0; i 100; i){log.shared_print(main, i);}t1.join();return 0;
}
死锁 adopt_lock当某个资源被两把以上的锁嵌套加锁且锁的顺序不一致时可能发生死锁。原因在于多个线程可能各自加了1把锁后同时在等待对方释放剩余的锁。最简单的解决方法是只要锁的顺序一致就不会死锁。#includeiostream
#includethread
#includestring
#includemutex
#includefstreamclass LogFile
{std::mutex m_mutex;//锁1std::mutex m_mutex2;//锁2std::ofstream f;
public:LogFile()//构造函数初始化时新建一个txt文件{f.open(log.txt);}void shared_print(std::string id, int value){std::lock_guardstd::mutex locker(m_mutex);//锁住m_mutex成员std::lock_guardstd::mutex locker2(m_mutex2);std::cout id : value std::endl;}void shared_print2(std::string id, int value){std::lock_guardstd::mutex locker2(m_mutex2);//【出现死所交换和下一行的位置即可】std::lock_guardstd::mutex locker(m_mutex);//std::lock_guardstd::mutex locker2(m_mutex2);std::cout id : value std::endl;}
};void function_1(LogFile log)
{for (int i 0; i -1000; i--)log.shared_print(std::string(from t1:), i);
}int main()//主线程
{LogFile log;std::thread t1(function_1, std::ref(log));//t1线程开始运行for (int i 0; i 1000; i){log.shared_print2(std::string(from main:), i);}t1.join();return 0;
}
某次运行结果如下程序运行到某时刻卡住了:from main::0
from main::1
省略...
from main::154
from main::155
from main::156
from main::157
from t1::0当程序比较复杂时手动方法管理加锁顺序可能相当麻烦这是就出现了adopt_lock参数来解决。locklock_guard的adopt_lock参数自动避免死锁问题。lock()可同时管理多个锁顺序无影响同时锁住多个锁若不可先释放然后继续尝试。 lock_guard()的adopt_lock参数即抛弃lock操作因为前面必须已加锁只使用其自动unlock功能。#includeiostream
#includethread
#includestring
#includemutex
#includefstreamclass LogFile
{std::mutex m_mutex;//锁1std::mutex m_mutex2;//锁2std::ofstream f;
public:LogFile(){f.open(log.txt);}void shared_print(std::string id, int value){std::lock(m_mutex, m_mutex2);//lock()同时管理多个锁std::lock_guardstd::mutex locker(m_mutex,std::adopt_lock);//adopt_lock即抛弃lock操作因为上句已加锁std::lock_guardstd::mutex locker2(m_mutex2, std::adopt_lock);//在析构时自动unlock()std::cout id : value std::endl;}void shared_print2(std::string id, int value){std::lock(m_mutex, m_mutex2);std::lock_guardstd::mutex locker2(m_mutex2, std::adopt_lock);std::lock_guardstd::mutex locker(m_mutex, std::adopt_lock);std::cout id : value std::endl;}
};void function_1(LogFile log)
{for (int i 0; i -1000; i--)log.shared_print(std::string(from t1:), i);
}int main()//主线程
{LogFile log;std::thread t1(function_1, std::ref(log));//t1线程开始运行for (int i 0; i 1000; i){log.shared_print2(std::string(from main:), i);}t1.join();return 0;
}
运行结果如下不会出现死锁from t1::0
from main::0
from t1::-1
from main::1
省略...
from t1::-997
from main::994
from t1::-998
from main::995
from t1::-999
from main::996
from main::997
from main::998
from main::999
请按任意键继续. . .
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/83942.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!