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

域名买卖网站/湖南网站排名

域名买卖网站,湖南网站排名,iis wordpress 500错误,网站推广方式组合文章目录第 2 章 管理线程2.2 传递参数给线程函数2.3 转移线程的所有权2.4在运行时选择线程数量2.5 标识线程第 3 章 在线程间共享数据、3.2.4 死锁:问题和解决方案3.2.6用std::unique_lock灵活锁定3.3 用于共享数据保护的替代工具3.3.1 在初始化时保护共享数据3.3.…

文章目录

    • 第 2 章 管理线程
        • 2.2 传递参数给线程函数
        • 2.3 转移线程的所有权
        • 2.4在运行时选择线程数量
        • 2.5 标识线程
    • 第 3 章 在线程间共享数据、
        • 3.2.4 死锁:问题和解决方案
        • 3.2.6用```std::unique_lock```灵活锁定
        • 3.3 用于共享数据保护的替代工具
            • 3.3.1 在初始化时保护共享数据
            • 3.3.2 保护很少更新的数据结构
            • 3.3.3 递归锁
    • 第 4 章 同步并发操作
            • 4.1.1 用条件变量等待条件
        • 4.2 使用```future```等待一次性事件
            • 4.2.1 从后台任务中返回值
            • 4.2.2 将任务与```future```相关联
            • 4.2.3 生成```std::promise```
            • 4.2.4 位```future```保存异常
            • 4.2.5 等待自多个线程
        • 4.3 有时间限制的等待
            • 4.3.1 时钟
            • 4.3.2 时间段
            • 4.3.3 时间点
            • 4.3.4 接受超时的函数

第 2 章 管理线程

2.2 传递参数给线程函数

#include<iostream>
#include <algorithm>
#include <string>
#include <list>
#include <memory>
#include <map>
#include <vector>
#include <mutex>
#include <thread>
using namespace  std;struct Status
{int value = 1;
};void DisplayStatus(const Status&status)
{cout << "status is " << status.value << endl;
}void UpdateStatus(Status &status)
{status.value++;DisplayStatus(status);
}class X
{
public:void do_something(int &n){cout << "do something" << endl;}
};int main()
{Status status;std::thread t(UpdateStatus, status);//这里的status并没有传入引用,而是传入了一份拷贝t.join();DisplayStatus(status);//线程执行完之后,status并没有被改变std::thread t2(UpdateStatus, ref(status));//这里传递了引用t2.join();DisplayStatus(status);//status在线程中被改变X x;int n = 5;//thread t3(&X::do_something, &x, n);这样是错误的thread t3(&X::do_something, &x,ref(n));//传递一个成员函数的指针作为函数t3.join();return 0;
}

2.3 转移线程的所有权

  std::thread是可移动的,而非可复制的。所以转移所有权要以移动操作来进行。
  explicit可以防止构造函数隐式自动转换

void some_function()
{}
void some_other_function()
{}int main()
{std::thread t1(some_function);std::thread t2 = std::move(t1);	//t1的控制权移动到了t2t1 = std::thread(some_other_function);//从临时对象中进行移动是自动的和隐式的,临时对象的控制权移动到t1std::thread t3;		//没有关联的线程t3 = std::move(t2);	//t2的控制权移动到了t3t1 = std::move(t3);//会导致程序终止,因为t1已经关联了线程return 0;
}

2.4在运行时选择线程数量

#include<iostream>
#include <algorithm>
#include <string>
#include <list>
#include <memory>
#include <map>
#include <vector>
#include <mutex>
#include <thread>
#include <numeric>
using namespace  std;template<typename Iterator, typename T>
struct accumulate_block
{void operator()(Iterator first, Iterator last, T&result){result = std::accumulate(first, last,result);}
};template<typename Iterator,typename T>
T parallel_accumulate(Iterator first, Iterator last, T init)
{unsigned long const length = std::distance(first, last);//计算两个迭代器之间的距离if (!length){return init;}unsigned long const min_per_thread = 25;unsigned long const max_threads = (length + min_per_thread - 1) / min_per_thread;/*给定程序执行时能够真正并发运行的线程数量的指示,在多核系统上它可能是CPU核心的数量*/unsigned long const hardware_threads = std::thread::hardware_concurrency();			unsigned long const num_threads = std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads);unsigned long const block_size = length / num_threads;std::vector<T> results(num_threads);std::vector<std::thread> threads(num_threads - 1);Iterator block_start = first;for (unsigned long i = 0; i < (num_threads - 1); ++i){Iterator block_end = block_start;std::advance(block_end, block_size);	//将迭代器移动一定的距离threads[i] = std::thread(accumulate_block<Iterator,T>(),block_start, block_end, ref(results[i]));block_start = block_end;}accumulate_block<Iterator,T>()(block_start, last, results[num_threads - 1]);std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));return std::accumulate(results.begin(), results.end(), init);
}int main()
{std::vector<int> v;for (int i = 1; i <= 99; i++){v.push_back(i);}int result = parallel_accumulate<decltype(v.begin()),int>(v.begin(), v.end(),0);cout << result << endl;return 0;
}

其他知识点:关于std::mem_fn

class ClassA
{
public:void do_something(int n){}
};int main()
{ClassA a;auto memeber_fun = std::mem_fn(&ClassA::do_something);memeber_fun(a,1);return 0;
}

2.5 标识线程

  • 线程标识符可以通过与之相关的std::thread对象中通过调用get_id()成员函数来获得。
  • 当前线程的标识符可以通过调用std::this_thread::get_id()获得

第 3 章 在线程间共享数据、

竞争条件一般是时间敏感的,他们常常在应用程序运行于调试工具下时完全消失,因为调试工具会影响程序的时间,即使是轻微的。

3.2.4 死锁:问题和解决方案

死锁的四个条件

  • 互斥
  • 不可抢占
  • 占有且等待
  • 循环等待

解决死锁的方案

  • 一次性获取所有锁
  • 避免嵌套锁 如果已经持有一个锁,就不该再获取锁
  • 以固定的顺序获取锁
  • 占有锁时避免调用用户代码,因为用户代码中可能会申请锁

使用std::lock同时锁定多个锁
std::adopt_lock告知std::lock_guard对象该互斥元已被锁定,并且他们只应沿用互斥元上已有锁的所有权,而不是试图在构造函数中锁定互斥元

class some_big_object {};
void swap(some_big_object &lhs, some_big_object &rhs);class X
{
private:some_big_object some_detail;std::mutex m;public:X(const some_big_object&sd ):some_detail(sd){}friend void swap(X &lhs, X&rhs){if (&lhs == &rhs){return;}std::lock(lhs.m, rhs.m);		//同时锁定多个锁std::lock_guard<std::mutex> lock_a(lhs.m, std::adopt_lock);std::lock_guard<std::mutex> lock_b(rhs.m, std::adopt_lock);//std::adopt_lock告知std::lock_guard对象该互斥元已被锁定,并且他们只应沿用互斥元上已有锁的所有权,而不是试图在构造函数中锁定互斥元swap(lhs.some_detail, rhs.some_detail);}
};

3.2.6用std::unique_lock灵活锁定

  • std::unique_lock占用更多的空间并且使用起来比std::lock_guard略慢,但是更加灵活
  • std::unique_lock提供了lock()try_lock()unlock()三个成员函数。所以可以随时解锁,而不必非要等到析构。
class some_big_object {};
void swap(some_big_object &lhs, some_big_object &rhs);class X
{
private:some_big_object some_detail;std::mutex m;public:X(const some_big_object&sd ):some_detail(sd){}friend void swap(X &lhs, X&rhs){if (&lhs == &rhs){return;}std::unique_lock<std::mutex> lock_a(lhs.m, std::defer_lock);std::unique_lock<std::mutex> lock_b(rhs.m, std::defer_lock);std::lock(lock_a, lock_b);swap(lhs.some_detail, rhs.some_detail);}
};

std::unique_lock主要用于以下三种场景

  • 延迟锁定,如上文
  • 需要转移锁的所有权
  • 允许实例在备销毁之前撤回他们的锁,即随时可unlock

3.3 用于共享数据保护的替代工具

3.3.1 在初始化时保护共享数据
class some_resource
{
public:void do_something(){}
};
std::shared_ptr<some_resource> resource_ptr;
std::mutex resource_mutex;//安全,但是序列化问题足够大
void foo()
{std::unique_lock<std::mutex> lock(resource_mutex);if (!resource_ptr){resource_ptr.reset(new some_resource);}lock.unlock();resource_ptr->do_something();
}//臭名昭著的二次检查锁定,会有问题
//就算一个线程看到另一个线程写入指针,它也可能无法看到新创建的some_resource实例,即虽然指针不为空,但是还没有被初始化
void undefined_behaviour_with_double_checked_locking()
{if (!resource_ptr){std::lock_guard<std::mutex> lock(resource_mutex);if (!resource_ptr){resource_ptr.reset(new some_resource);}}resource_ptr->do_something();
}

使用std::call_once可以完美解决上述问题

class some_resource
{
public:void do_something(){}
};
std::shared_ptr<some_resource> resource_ptr;
std::once_flag resource_flag;void init_resource()
{resource_ptr.reset(new some_resource);
}void foo()
{std::call_once(resource_flag, init_resource);resource_ptr->do_something();
}
3.3.2 保护很少更新的数据结构

  比如有些数据很少更新,但是经常会读。这种情况下使用std::mutex就太悲观了,意味着不能同时读了。此时可以使用shared_mutex来实现解决读写问题,类似pthread的读写锁。std::shared_mutex在C++17中才实现,考虑到现在大部分编译器都还不支持,所以实际上都是使用boost::shared_mutex

  • 使用shared_mutex来同步,而不是mutex
  • 使用std::unique_lockstd::lock_guard来独占锁,即写锁
  • 使用boost::shared_lock来共享锁,即读锁。
class dns_entry{};
class dns_cache
{std::map<std::string, dns_entry> entries;mutable std::shared_mutex entry_mutex;	//mutable突破const的限制,即使再const函数中也可被改变
public:dns_entry find_entry(std::string const &domain) const{std::shared_lock<std::shared_mutex> lock(entry_mutex);const auto it = entries.find(domain);return(it == entries.end()) ? dns_entry() : it->second;}void update_or_add_entry(const std::string&domain, const dns_entry&entry){std::lock_guard<std::shared_mutex>lock(entry_mutex);entries[domain] = entry;}
};
3.3.3 递归锁

  在使用std::mutex的情况下,一个线程试图锁定其已经拥有的互斥元是错误的,并且试图这么做导致未定义行为。
  C++提供了std::recursive_mutex,可以在同一个线程中的单个实例上获取多个锁。在互斥元能够被另一个线程锁定前,必须释放所有的锁。
  大多数时间,如果你觉得需要一个递归互斥元,你可能反而需要改变你的设计。

第 4 章 同步并发操作

4.1.1 用条件变量等待条件
struct data_chunk{};
bool more_data_to_prepare() { return true; }
bool is_last_chunk(data_chunk) { return false; }
data_chunk prepare_data() { return data_chunk(); };
void process(data_chunk) {};std::mutex mut;
std::queue<data_chunk>data_queue;
std::condition_variable data_cond;void data_preparation_thread()
{while (more_data_to_prepare()){const data_chunk data= prepare_data();std::lock_guard<std::mutex> lock(mut);data_queue.push(data);data_cond.notify_one();		//通知等待中的线程}
}void data_processing_thread()
{while (true){std::unique_lock<std::mutex> lk(mut);data_cond.wait(lk, [] {return !data_queue.empty(); });//获取锁,查条件,条件不满足则释放锁继续等data_chunk data = data_queue.front();data_queue.pop();lk.unlock();process(data);if(is_last_chunk(data))break;}
}

4.2 使用future等待一次性事件

4.2.1 从后台任务中返回值

std::async可以传入参数来决定是否启动一个新线程

  • std::launch::async:在新线程中运行
  • std::launch::deferred:在wait()get()中运行
  • std::launch::async|std::launch::deferred(默认):由具体实现来选择
struct X
{void foo(int, std::string const &) {};std::string bar(const std::string &) { return std::string(); };
};
X x;
auto f1 = std::async(&X::foo, &x, 42, "hello");//调用p->foo(42,"hello"),其中p是&x
auto f2 = std::async(&X::bar, x, "goodbye");	//调用tempx.bar("goodbye"),其中tempx是x的副本,所以不会对x有影响struct Y
{double operator()(double) { return 0; };
};
Y y;
auto f3 = std::async(Y(), 3.141);//调用tempy(3.141),其中tempy是从Y()移动构造的
auto f4 = std::async(std::ref(y), 2.718);//调用y(2.718)X baz(X&) {};
auto f5 = std::async(baz, std::ref(x));//调用baz(x)
4.2.2 将任务与future相关联
std::mutex m;
std::deque<std::packaged_task<void()>> tasks;std::condition_variable task_cond;bool gui_shutdown_message_recived();
void get_and_process_gui_message();void gui_thread()
{while (!gui_shutdown_message_recived()){get_and_process_gui_message();std::unique_lock<std::mutex> lk(m);task_cond.wait(lk, [] {return !tasks.empty(); });std::packaged_task<void()> task = std::move(tasks.front());tasks.pop_front();lk.unlock();task();}
}std::thread gui_bg_thread(gui_thread);
template<typename Func>
std::function<void> post_task_for_gui_thread(Func f)
{std::packaged_task<void()> task(f);std::future<void> res = task.get_future();std::lock_guard<std::mutex>lk(m);tasks.push_back(std::move(task));task_cond.notify_one();return res;
}
4.2.3 生成std::promise

参考:C++11多线程-异步运行(1)之std::promise

void read(std::future<std::string> *future) {// future会一直阻塞,直到有值到来std::cout << future->get() << std::endl;
}int main() {// promise 相当于生产者std::promise<std::string> promise;// future 相当于消费者, 右值构造std::future<std::string> future = promise.get_future();// 另一线程中通过future来读取promise的值std::thread thread(read, &future);// 让read等一会儿:)std::this_thread::sleep_for(seconds(1));// promise.set_value("hello future");// 等待线程执行完成thread.join();return 0;
}
4.2.4 位future保存异常

可以通过some_promise.set_exception()来让future抛出异常

4.2.5 等待自多个线程
  • 对于std::future而言,只有一个线程可以获取值,因为在首次调用get()后,就没有任何可获取的值留下了。
  • 如果每个线程都通过自己的std::shared_future对象来访问该状态,那么就是安全的。

4.3 有时间限制的等待

4.3.1 时钟
  • std::chrono::system_clock是系统时钟,是不匀速(steady)时钟,因为系统时钟可以调整。std::chrono::system_clock::now()返回的是当前时间。
  • std::chrono::steady_clock是匀速时钟
  • std::chrono::high_resolution_clock提供的是所有类库时钟中最小可能的节拍周期(和可能的最高精度),它实际上可能是其他时钟之一的typedef实际上,在vs2015中,该时钟就是steadt_clocktypedef
4.3.2 时间段

  时间段由std::chrono::duration<>来表示,实际上我们常用的milliseconds等都是durationtypedef。在VS2015中有以下定义:

typedef ratio<1, 1000000000000000000LL> atto;
typedef ratio<1, 1000000000000000LL> femto;
typedef ratio<1, 1000000000000LL> pico;typedef ratio<1, 1000000000> nano;
typedef ratio<1, 1000000> micro;
typedef ratio<1, 1000> milli;
typedef ratio<1, 100> centi;
typedef ratio<1, 10> deci;
typedef ratio<10, 1> deca;
typedef ratio<100, 1> hecto;
typedef ratio<1000, 1> kilo;
typedef ratio<1000000, 1> mega;
typedef ratio<1000000000, 1> giga;typedef ratio<1000000000000LL, 1> tera;
typedef ratio<1000000000000000LL, 1> peta;
typedef ratio<1000000000000000000LL, 1> exa;// duration TYPEDEFS
typedef duration<long long, nano> nanoseconds;
typedef duration<long long, micro> microseconds;
typedef duration<long long, milli> milliseconds;
typedef duration<long long> seconds;
typedef duration<int, ratio<60> > minutes;
typedef duration<int, ratio<3600> > hours;

  基于时间段的等待使用类库内部的匀速时钟来衡量时间,因此35毫秒意味着35毫秒的逝去时间,即便系统时钟在等待期间进行调整。

4.3.3 时间点
  • 一个特定的时间点被称为时钟的纪元*(epoch),典型的纪元包括1970年1月1日00:00,以及运行应用程序的计算机引导启动的瞬间。是不变的。
  • 时钟的时间点是通过std::chrono::time_point<>类模板的实例来表示的,第一个模板参数指定其参考的时钟,第二个模板参数指定计量单位。

计算两个时间点之间长度的时间段

auto start = std::chrono::high_resolution_clock::now();
do_sometiong();
auto stop = std::chrono::high_resolution_clock::now();
std::cout << "do_something() took " << std::chrono::duration<double, std::chrono::seconds>(stop - start).count() << " seconds" << std::endl;

等待一个具有超时的条件变量

bool wait_loop()
{auto const timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(500);//匀速时钟,不可变std::unique_lock<std::mutex> lk(m);while (!done){if(cv.wait_until(lk,timeout)==std::cv_status::timeout)break;}return true;
}bool wait_loop2()
{auto timeout = std::chrono::duration<long long, std::ratio<1,1000>>(20);std::unique_lock<std::mutex> lk(m);while (!done){if(cv.wait_for(lk,timeout)==std::cv_status::timeout)break;//等价于:if (cv.wait_for(lk, std::chrono::microseconds(20))==std::cv_status::timeout)break;}return true;
}
4.3.4 接受超时的函数
类/命名空间函数返回值
std::this_thread命名空间sleep_for(duration)
sleep_until(time_point)
不可用
std::condition_variable
std::condition_variable_any
wait_for(lock,duration)
wait_until(lock,time_point)
std::cv_status::timeout
std::cv_status::no_timeout
wait_for(lock,duration,predicate)
wait_until(lock,time_point,predicate)
bool——当唤醒时predicate的返回值
std::timed_mutexstd::recursive_timed_mutextry_lock_for(duration)
try_lock_until(time_point)
bool—true如果获得了锁,否则false
std::unique_lock<TimeLockable>
http://www.jmfq.cn/news/4794697.html

相关文章:

  • 做网站设计怎么进企业/推广产品怎么发朋友圈
  • 企业网络需求分析报告/深圳优化公司统高粱seo
  • 网站劫持怎么做/seodao cn
  • 做网站的标准流程/怎么自己弄一个网站
  • app开发和网站开发/月入百万的游戏代理
  • 公司做网站要注意什么/网络营销的职能是什么
  • 公司弄个网站多少钱/seo站长查询
  • 怎么做app和网站购物车/安卓优化大师旧版
  • 做网站咋么插入背景图片/阿里云域名注册官网网址
  • linux网站做301重定向/免费seo营销优化软件下载
  • 青岛做网站的好公司/武汉网优化seo公司
  • 网页免费模板/网站优化搜索排名
  • 某企业网站搜索引擎优化/北京seo不到首页不扣费
  • 专业的移动网站建设公司排名/交换友链
  • wordpress上传小视频/seo网站管理招聘
  • 视频网站推广怎么做/西安百度搜索排名
  • 嘉兴网站关键词/站长工具大全集
  • 优化网站专题/东莞网站制作公司联系方式
  • 家用电脑做网站服务器/网站制作流程是什么
  • 门户网站建设进度/国内快速建站
  • 外贸b2b选品/零基础seo入门教学
  • 清苑区建设网站找那家公司/长沙网动网络科技有限公司
  • 百度免费邮箱注册/seo站长工具下载
  • 厦门电子网站建设/十大广告投放平台
  • 网站中竖导航栏怎么做/开发一个网站的步骤流程
  • 如何建立自己的购物网站/网络营销属于什么专业类型
  • 葡萄城网站建设/网上电商怎么做
  • 营销型企业网站建设 广义的空间/网站站点
  • wordpress网站配置文件/企业短视频推广
  • 专业写作网站/怎么建立公司网站