当前位置: 首页 > news >正文

杭州网站设计公司价格黑帽seo技术论坛

杭州网站设计公司价格,黑帽seo技术论坛,17网站一起做网店 睡衣,用asp.net做网站C11学习 一、多线程 1、模板线程是以右值传递的 template <class Fn, class... Args> explicit thread(Fn&& fn, Args&&... args)则需要使用到std::ref和std::cref很好地解决了这个问题&#xff0c;std::ref 可以包装按引用传递的值。 std::cref 可以…

C++11学习

一、多线程

1、模板线程是以右值传递的

template <class Fn, class... Args> explicit thread(Fn&& fn, Args&&... args)

则需要使用到std::refstd::cref很好地解决了这个问题,std::ref 可以包装按引用传递的值。
std::cref 可以包装按const引用传递的值。

// Compiler: MSVC 19.29.30038.1
// C++ Standard: C++17
#include <iostream>
#include <thread>
using namespace std;
template<class T> void changevalue(T &x, T val) {x = val;
}
int main() {thread th[100];int nums[100];for (int i = 0; i < 100; i++)th[i] = thread(changevalue<int>, ref(nums[i]), i+1);for (int i = 0; i < 100; i++) {th[i].join();cout << nums[i] << endl;}return 0;
}

2、线程一些注意事项

线程是在thread对象被定义的时候开始执行的,而不是在调用join函数时才执行的,调用join函数只是阻塞等待线程结束并回收资源。
分离的线程(执行过detach的线程)会在调用它的线程结束或自己结束时释放资源。
线程会在函数运行完毕后自动释放,不推荐利用其他方法强制结束线程,可能会因资源未释放而导致内存泄漏。
没有执行join或detach的线程在程序结束时会引发异常

3、std::mutex互斥锁

三个方法

lock  上锁
unlock 解锁
bool try_lock()  尝试将mutex上锁。如果mutex未被上锁,则将其上锁并返回true;如果mutex已被锁则返回false。

4、std::atomic & atomic_flag

意思是该类型的变量是原子类型的操作。因为mutex的资源浪费较大,总是要上锁解锁的。引入atomic

std::atomic_int`只是`std::atomic<int>
atomic_int n = 0;  表示定义一个int类型的原子属性的变量n,他是线程安全的
atomic() noexcept = default默认构造函数构造一个atomic对象(未初始化,可通过atomic_init进行初始化)
constexpr atomic(T val) noexcept初始化构造函数构造一个atomic对象,用val的值来初始化

atomic_flag,原子布尔类型,不同于 std::atomic , std::atomic_flag 不提供加载或存储操作。

成员函数

(构造函数)构造 atomic_flag (公开成员函数)
operator=赋值运算符 (公开成员函数)
clear原子地设置标志为 false (公开成员函数)
test_and_set原子地设置标志为 true 并获得其先前值 (公开成员函数)
#include <thread>
#include <vector>
#include <iostream>
#include <atomic>//ATOMIC_FLAG_INIT 置为false
std::atomic_flag lock = ATOMIC_FLAG_INIT;void f(int n)
{for (int cnt = 0; cnt < 100; ++cnt) {//std::memory_order_acquire 内存访问while (lock.test_and_set(std::memory_order_acquire))  // 获得锁; // 自旋std::cout << "Output from thread " << n << '\n';lock.clear(std::memory_order_release);               // 释放锁}
}int main()
{std::vector<std::thread> v;for (int n = 0; n < 10; ++n) {v.emplace_back(f, n);}for (auto& t : v) {t.join();}
}

5、std::async&std::future&std::shared_future

std::async定义在future头文件中,新的线程类,执行效率更高于thread,并且可以选择同步异步执行,还有返回值可以选择调用时间。

重载版本作用
template <class Fn, class… Args>
future<typename result_of<Fn(Args…)>::type>
async (Fn&& fn, Args&&… args)
异步或同步(根据操作系统而定)以args为参数执行fn
同样地,传递引用参数需要std::refstd::cref
template <class Fn, class… Args>
future<typename result_of<Fn(Args…)>::type>
async (launch policy, Fn&& fn, Args&&… args);
异步或同步(根据policy参数而定(见下文))以args为参数执行fn,引用参数同上。std::launch有2个枚举值和1个特殊值:枚举值:launch::async、launch::deferred、launch::async
// Compiler: MSVC 19.29.30038.1
// C++ Standard: C++17
#include <iostream>
#include <thread>
#include <future>
using namespace std;
int main() {async(launch::async, [](const char *message){cout << message << flush;}, "Hello, ");cout << "World!" << endl;return 0;
}

其async的返回值std::future,是一个模板对象。

其成员函数有

一般:T get()
当类型为引用:R& future<R&>::get()
当类型为void:void future::get()
阻塞等待线程结束并获取返回值。
若类型为void,则与future::wait()相同。
只能调用一次。
void wait() const阻塞等待线程结束
template <class Rep, class Period>
future_status wait_for(const chrono::duration<Rep,Period>& rel_time) const;
阻塞等待rel_time(rel_time是一段时间),
若在这段时间内线程结束则返回future_status::ready
若没结束则返回future_status::timeout
若async是以launch::deferred启动的,则不会阻塞并立即返回future_status::deferred

std::future的作用并不只有获取返回值,它还可以检测线程是否已结束、阻塞等待,所以对于返回值是void的线程来说,future也同样重要。

// Compiler: MSVC 19.29.30038.1
// C++ Standard: C++17
#include <iostream>
#include <future>
using namespace std;
void count_big_number() {// C++14标准中,可以在数字中间加上单// 引号 ' 来分隔数字,使其可读性更强for (int i = 0; i <= 10'0000'0000; i++);
}
int main() {future<void> fut = async(launch::async, count_big_number);cout << "Please wait" << flush;// 每次等待1秒while (fut.wait_for(chrono::seconds(1)) != future_status::ready)cout << '.' << flush;cout << endl << "Finished!" << endl;return 0;
}

std::shared_future类模板 std::shared_future 提供访问异步操作结果的机制,类似 std::future ,除了允许多个线程等候同一共享状态。不同于仅可移动的 std::future (故只有一个实例能指代任何特定的异步结果),std::shared_future 可复制而且多个 shared_future 对象能指代同一共享状态。

若每个线程通过其自身的 shared_future 对象副本访问,则从多个线程访问同一共享状态是安全的。

#include <iostream>
#include <future>
#include <chrono>int main()
{   std::promise<void> ready_promise, t1_ready_promise, t2_ready_promise;std::shared_future<void> ready_future(ready_promise.get_future());std::chrono::time_point<std::chrono::high_resolution_clock> start;auto fun1 = [&, ready_future]() -> std::chrono::duration<double, std::milli> {t1_ready_promise.set_value();ready_future.wait(); // 等待来自 main() 的信号return std::chrono::high_resolution_clock::now() - start;};auto fun2 = [&, ready_future]() -> std::chrono::duration<double, std::milli> {t2_ready_promise.set_value();ready_future.wait(); // 等待来自 main() 的信号return std::chrono::high_resolution_clock::now() - start;};auto result1 = std::async(std::launch::async, fun1);auto result2 = std::async(std::launch::async, fun2);// 等待线程变为就绪t1_ready_promise.get_future().wait();t2_ready_promise.get_future().wait();// 线程已就绪,开始时钟start = std::chrono::high_resolution_clock::now();// 向线程发信使之运行ready_promise.set_value();std::cout << "Thread 1 received the signal "<< result1.get().count() << " ms after start\n"<< "Thread 2 received the signal "<< result2.get().count() << " ms after start\n";
}

6、std::promise

是实际上是std::future的一个包装,但是作用确实想实现线程函数的左值引用,将函数执行结果带回来。

一般:
void set_value (const T& val)
void set_value (T&& val)
当类型为引用:void promise<R&>::set_value (R& val)
当类型为void:void promise::set_value (void)
设置promise的值并将共享状态设为ready(将future_status设为ready)
void特化:只将共享状态设为ready
future get_future()构造一个future对象,其值与promise相同,status也与promise相同
// Compiler: MSVC 19.29.30038.1
// C++ Standard: C++17
#include <iostream>
#include <thread>
#include <future> // std::promise std::future
using namespace std;template<class ... Args> decltype(auto) sum(Args&&... args) {return (0 + ... + args);
}template<class ... Args> void sum_thread(promise<long long> &val, Args&&... args) {val.set_value(sum(args...));  //设置值
}int main() {promise<long long> sum_value;//目的还是传递左值引用thread get_sum(sum_thread<int, int, int>, ref(sum_value), 1, 10, 100);cout << sum_value.get_future().get() << endl; //获取值get_sum.join(); // 感谢评论区 未来想做游戏 的提醒return 0;
}

6、std::this_thread中的一些静态方法

std::thread::id get_id() noexcept获取当前线程id
template<class Rep, class Period>
void sleep_for( const std::chrono::duration<Rep, Period>& sleep_duration )
等待sleep_durationsleep_duration是一段时间)
void yield() noexcept暂时放弃线程的执行,将主动权交给其他线程
(放心,主动权还会回来)
template <class Clock, class Duration> void sleep_until (const chrono::time_point<Clock,Duration>& abs_time);等到到abs_time这个时间到来再执行
#include <iostream>
#include <thread>
#include <atomic>
using namespace std;
atomic_bool ready = 0;  //原子类型变量 bool类型  atomic<bool>
// uintmax_t ==> unsigned long long
void sleep(uintmax_t ms) {this_thread::sleep_for(chrono::milliseconds(ms));
}
void count() {while (!ready) this_thread::yield();//暂时交出cpu执行,for (int i = 0; i <= 20'0000'0000; i++);cout << "Thread " << this_thread::get_id() << " finished!" << endl;return;
}
int main() {thread th[10];for (int i = 0; i < 10; i++)th[i] = thread(::count);sleep(5000);ready = true;cout << "Start!" << endl;for (int i = 0; i < 10; i++)th[i].join();return 0;
}
// this_thread::sleep_for example
#include <iostream> // std::cout
#include <iomanip> // std::put_time
#include <thread> // std::this_thread::sleep_until
#include <chrono> // std::chrono::system_clock
#include <ctime> // std::time_t, std::tm, std::localtime, std::mktime
int main()
{
using std::chrono::system_clock;
std::time_t tt = system_clock::to_time_t (system_clock::now());
struct std::tm * ptm = std::localtime(&tt);
std::cout << "Current time: " << std::put_time(ptm,"%X") << '\n';
std::cout << "Waiting for the next minute to begin...\n";
++ptm->tm_min; ptm->tm_sec=0;
std::this_thread::sleep_until (system_clock::from_time_t (mktime(ptm)));
std::cout << std::put_time(ptm,"%X") << " reached!\n";
return 0;
}

7、std::lock_guard & std::unique_lock

成员函数

(构造函数)构造 lock_guard ,可选地锁定给定的互斥 (公开成员函数)
(析构函数)析构 lock_guard 对象,解锁底层互斥 (公开成员函数)

lock_guard( mutex_type& m, std::adopt_lock_t t );的构造方法的第二个参数

std::defer_lock_t, std::try_to_lock_t, std::adopt_lock_t 三个值。是用于为 std::lock_guard 、 std::scoped_lock 、 std::unique_lock 和 std::shared_lock 指定锁定策略的空类标签类型。

defer_lock_t不获得互斥的所有权try_to_lock_t尝试获得互斥的所有权而不阻塞adopt_lock_t假设调用方线程已拥有互斥的所有权

构造互斥锁的写法,就是会在lock_guard构造函数里加锁,在析构函数里解锁,达到自动加锁,解锁的目的。因此lock_guard的作用域就是锁的范围。

#include <iostream>
#include <thread>
#include <string>
#include <mutex>
using namespace std;mutex mt;
void thread_task()
{for (int i = 0; i < 10; i++){lock_guard<mutex> guard(mt);cout << "print thread: " << i << endl;}
}int main()
{thread t(thread_task);for (int i = 0; i > -10; i--){lock_guard<mutex> guard(mt);cout << "print main: " << i << endl;}t.join();return 0;
}

虽然lock_guard挺好用的,但是有个很大的缺陷,在定义lock_guard的地方会调用构造函数加锁,在离开定义域的话lock_guard就会被销毁,调用析构函数解锁。这就产生了一个问题,如果这个定义域范围很大的话,那么锁的粒度就很大,很大程序上会影响效率。所以为了解决lock_guard锁的粒度过大的原因,unique_lock就出现了。

unique_lock<mutex> unique(mt);

这个会在构造函数加锁,然后可以利用unique.unlock()来解锁,所以当你觉得锁的粒度太多的时候,可以利用这个来解锁,而析构的时候会判断当前锁的状态来决定是否解锁,如果当前状态已经是解锁状态了,那么就不会再次解锁,而如果当前状态是加锁状态,就会自动调用unique.unlock()来解锁。而lock_guard在析构的时候一定会解锁,也没有中途解锁的功能。方便肯定是有代价的,unique_lock内部会维护一个锁的状态,所以在效率上肯定会比lock_guard慢。

(构造函数)构造 unique_lock ,可选地锁定提供的互斥 (公开成员函数)
(析构函数)若占有关联互斥,则解锁之 (公开成员函数)
operator=若占有则解锁互斥,并取得另一者的所有权 (公开成员函数)
锁定
lock锁定关联互斥 (公开成员函数)
try_lock尝试锁定关联互斥,若互斥不可用则返回 (公开成员函数)
try_lock_for试图锁定关联的可定时锁定 (TimedLockable) 互斥,若互斥在给定时长中不可用则返回 (公开成员函数)
try_lock_until尝试锁定关联可定时锁定 (TimedLockable) 互斥,若抵达指定时间点互斥仍不可用则返回 (公开成员函数)
unlock解锁关联互斥 (公开成员函数)
修改器
swap与另一 std::unique_lock 交换状态 (公开成员函数)
release将关联互斥解关联而不解锁它 (公开成员函数)
观察器
mutex返回指向关联互斥的指针 (公开成员函数)
owns_lock测试锁是否占有其关联互斥 (公开成员函数)
operator bool测试锁是否占有其关联互斥
#include <mutex>
#include <thread>
#include <chrono>struct Box {explicit Box(int num) : num_things{num} {}int num_things;std::mutex m;
};void transfer(Box &from, Box &to, int num)
{// 仍未实际取锁std::unique_lock<std::mutex> lock1(from.m, std::defer_lock);std::unique_lock<std::mutex> lock2(to.m, std::defer_lock);// 锁两个 unique_lock 而不死锁std::lock(lock1, lock2);from.num_things -= num;to.num_things += num;// 'from.m' 与 'to.m' 互斥解锁于 'unique_lock' 析构函数
}int main()
{Box acc1(100);Box acc2(50);std::thread t1(transfer, std::ref(acc1), std::ref(acc2), 10);std::thread t2(transfer, std::ref(acc2), std::ref(acc1), 5);t1.join();t2.join();
}

8、condition_variable 条件变量

condition_variable 类是同步原语,能用于阻塞一个线程,或同时阻塞多个线程,直至另一线程修改共享变量(条件)并通知 condition_variable

-------------有意修改变量的线程必须
获得 std::mutex (常通过 std::lock_guard )
在保有锁时进行修改
在 std::condition_variable 上执行 notify_one 或 notify_all (不需要为通知保有锁)
即使共享变量是原子的,也必须在互斥下修改它,以正确地发布修改到等待的线程。
-----------任何有意在 std::condition_variable 上等待的线程必须
在与用于保护共享变量者相同的互斥上获得 std::unique_lock<std::mutex>
执行下列之一:
检查条件,是否为已更新或提醒它的情况
执行 wait 、 wait_for 或 wait_until ,等待操作自动释放互斥,并悬挂线程的执行。
condition_variable 被通知时,时限消失或虚假唤醒发生,线程被唤醒,且自动重获得互斥。之后线程应检查条件,若唤醒是虚假的,则继续等待。
或者
使用 wait 、 wait_for 及 wait_until 的有谓词重载,它们包揽以上三个步骤

std::condition_variable 只可与 std::unique_lock<std::mutex> 一同使用

成员函数

(构造函数)构造对象 (公开成员函数)
(析构函数)析构对象 (公开成员函数)
operator=[被删除]不可复制赋值 (公开成员函数)
通知
notify_one通知一个等待的线程 (公开成员函数)
notify_all通知所有等待的线程 (公开成员函数)
等待
wait阻塞当前线程,直到条件变量被唤醒 (公开成员函数)
wait_for阻塞当前线程,直到条件变量被唤醒,或到指定时限时长后 (公开成员函数)
wait_until阻塞当前线程,直到条件变量被唤醒,或直到抵达指定时间点 (公开成员函数)
原生句柄
native_handle返回原生句柄
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;void worker_thread()
{// 等待直至 main() 发送数据std::unique_lock<std::mutex> lk(m);cv.wait(lk, []{return ready;});//阻塞当前线程,直到条件变量被唤醒 (公开成员函数)// 等待后,我们占有锁。std::cout << "Worker thread is processing data\n";data += " after processing";// 发送数据回 main()processed = true;std::cout << "Worker thread signals data processing completed\n";// 通知前完成手动解锁,以避免等待线程才被唤醒就阻塞(细节见 notify_one )lk.unlock();cv.notify_one();
}int main()
{std::thread worker(worker_thread);data = "Example data";// 发送数据到 worker 线程{std::lock_guard<std::mutex> lk(m);ready = true;std::cout << "main() signals data ready for processing\n";}cv.notify_one();// 等候 worker{std::unique_lock<std::mutex> lk(m);cv.wait(lk, []{return processed;});}std::cout << "Back in main(), data = " << data << '\n';worker.join();
}

总结:C++多线程,涉及5个头文件

thread.hthread  类 (成员方法)thread 构造函数join 等待结束detach 分离线程,则无需等待结束this_thread 命名空间(静态方法)get_id  获取当前线程idyield 暂时交出cpu执行权sleep_for 睡眠等待函数sleep_until 等待到下一个具体的时间
mutex.hmutex 互斥锁lock_guard  配合互斥锁,达到互斥锁作用域范围内的自动上锁解锁unique_lock 在lock_guard基础上加了可以手动解锁的接口unlockatomic.hatomic  原子化变量atomic_flag 原子布尔类型condition_variable.hcondition_variablewait  阻塞当前线程,直到条件变量被唤醒 (公开成员函数)wait_for  阻塞当前线程,直到条件变量被唤醒,或到指定时限时长后 (公开成员函数)wait_until  阻塞当前线程,直到条件变量被唤醒,或直到抵达指定时间点 (公开成员函数)notify_ont  通知一个等待的线程 (公开成员函数)notify_all  通知所有等待的线程 (公开成员函数)condition_variable_any   std::condition_variable 的泛化waitwait_forwait_untilnotify_ontnotify_all		
future.hfuture   类似一个针对线程的类模板对象,可以对线程进行管理的。shared_future  不同于仅可移动的 std::future (故只有一个实例能指代任何特定的异步结果),std::shared_future 可复制而且多个 shared_future 对象能指代同一共享状态。promise  类似futurepackaged_task
http://www.shuangfujiaoyu.com/news/28134.html

相关文章:

  • 枣庄市住房和城乡建设局网站免费html网站制作成品
  • 氧os哪个网站做的最好域名注册需要什么条件
  • 唐山做网站公司永久免费进销存管理软件手机版
  • 做网站需要多大的内存专业拓客公司联系方式
  • 在线动画手机网站模板下载百度推广靠谱吗
  • 爱站网官网关键词查询seo优化包括什么
  • 物流网站建设哪个好浙江seo关键词
  • 做外贸到什么网站上发布比较好建立网站的基本流程
  • 网站如何在推广seo外包费用
  • 毕业设计网站模板关键词的优化方法
  • 怎么样自己制作网站下载班级优化大师并安装
  • 珠海横琴建设局网站国际最新新闻
  • 为什么建设厅的网站不好打开网络广告的发布方式包括
  • 织梦可以做论坛网站吗优化服务
  • 适合个人做的网站有哪些东西百度开户代理公司
  • 谢岗网站建设公司网站模版
  • 建站模板安装视频教程全集seo顾问服务 品达优化
  • 网站设计 珠海游戏推广工作好做吗
  • 广州营销型网站建设怎么做营销推广
  • 网站制作 成都微信推广方式有哪些
  • 自己做网站推广试玩电商运营公司简介
  • 建设文化网站的目的和意义自己做一个网站要多少钱
  • 怎么做自己的外卖网站怎么弄自己的网站
  • 记事本做网站怎么不行啦青岛seo软件
  • 电子商务电商网站设计提高工作效率的句子
  • 北京网站制作网站优化什么是seo和sem
  • 建设网站的费用属于百度词条优化
  • 口腔门诊建设网站推广引流方法与渠道
  • 双峰做网站比较靠谱的推广公司
  • 网站建设如何报价企业营销策划公司