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

做一个企业网站要多久ac68u做网站

做一个企业网站要多久,ac68u做网站,网站seo优化心得,wordpress图片地址优化C11并发与多线程 1. 线程是进程中的实际运作单位 并发#xff1a;两个或者更多的任务#xff08;独立的活动#xff09;同时发生#xff08;进行#xff09;#xff1a;一个程序同时执行多个独立的任务 进程#xff1a;一个可执行程序运行起来了#xff0c;就叫创建了…C11并发与多线程 1. 线程是进程中的实际运作单位 并发两个或者更多的任务独立的活动同时发生进行一个程序同时执行多个独立的任务 进程一个可执行程序运行起来了就叫创建了一个进程。进程就是运行起来的可执行程序 线程进程中的实际运作单位 2. 线程 创建线程 #include iostream #include thread // ①using namespace std; // ②void hello() { // ③cout Hello World from new thread. endl; }int main() {thread t(hello); // ④t.join(); // ⑤return 0; }对于这段代码说明如下 为了使用多线程的接口我们需要#include thread头文件。为了简化声明本文中的代码都将using namespace std;。新建线程的入口是一个普通的函数它并没有什么特别的地方。创建线程的方式就是构造一个thread对象并指定入口函数。与普通对象不一样的是此时编译器便会为我们创建一个新的操作系统线程并在新的线程中执行我们的入口函数。关于join函数在下文中讲解。 在linux下编译 g 01_hello_thread.cpp -o 01test -pthread传递参数给入口函数 #includeiostream #includethread #includestring using namespace std;void hello(string name){coutWelcome to nameendl; }int main(){thread t(hello,Hang Zhou);t.join();return 0; }join和detach API说明join等待线程完成其执行detach允许线程独立执行 join调用此接口时当前线程会一直阻塞直到目标线程执行完成。 detachdetach是让目标线程成为守护线程daemon threads。一旦detach之后目标线程将独立执行即便其对应的thread对象销毁也不影响线程的执行。 如果在thread对象销毁的时候我们还没有做决定则thread对象在析构函数出将调用std::terminate()从而导致我们的进程异常退出。 通过joinable()接口查询是否可以对它们进行join或者detach。 管理当前线程 APIC标准说明yieldC11让出处理器重新调度各执行线程get_idC11返回当前线程的线程 idsleep_forC11使当前线程的执行停止指定的时间段sleep_untilC11使当前线程的执行停止直到指定的时间点 #include chrono #include ctime #include iomanip #include iostream #include sstream #include thread using namespace std;void print_time(){auto now chrono::system_clock::now();auto in_time_t chrono::system_clock::to_time_t(now);std::stringstream ss;ss put_time(localtime(in_time_t),%Y-%m-%d %X);cout now is: ss.str()endl; } void sleep_thread(){this_thread::sleep_for(chrono::seconds(3));cout [thread-this_thread::get_id()] is waking upendl; } void loop_thread() {for (int i 0; i 10; i) {cout [thread- this_thread::get_id() ] print: i endl;} }int main() {print_time();thread t1(sleep_thread);thread t2(loop_thread);t1.join();t2.detach();print_time();return 0; }这段代码使用了C的标准库chrono、ctime、iomanip、iostream、sstream和thread。 函数print_time用于获取当前的系统时间并以特定的格式打印出来。它使用了C的chrono库来获取当前时间并使用localtime函数将时间转换为本地时间然后使用put_time函数将时间以指定的格式进行格式化输出。 函数sleep_thread用于使当前线程休眠3秒并在休眠结束后输出一条消息表明线程已经唤醒。它使用了C的thread库中的sleep_for函数来使当前线程休眠。this_thread::get_id()函数可以获取当前线程的ID。 函数loop_thread用于打印从0到9的整数并输出打印的线程ID。它在一个循环中打印数值每次打印后会自动进行下一次迭代。 在main函数中首先调用print_time函数打印当前时间。然后创建了两个线程t1和t2分别执行sleep_thread和loop_thread函数。线程t1会调用sleep_thread函数休眠3秒而线程t2会在循环中执行loop_thread函数。使用t1.join()语句可以等待线程t1执行完毕而t2.detach()语句则将线程t2与主线程分离使得线程t2在后台执行而不会影响主线程的运行。最后再次调用print_time函数打印当前时间并返回0表示程序正常结束。 now is: 2023-09-21 19:22:24 [thread-140221292599040] print: 0 [thread-140221292599040] print: 1 [thread-140221292599040] print: 2 [thread-140221292599040] print: 3 [thread-140221292599040] print: 4 [thread-140221292599040] print: 5 [thread-140221292599040] print: 6 [thread-140221292599040] print: 7 [thread-140221292599040] print: 8 [thread-140221292599040] print: 9 [thread-140221300991744] is waking up now is: 2023-09-21 19:22:27一次调用 APIC标准说明call_onceC11即便在多线程环境下也能保证只调用某个函数一次once_flagC11与call_once配合使用 有些任务需要执行一次并且我们只希望它执行一次例如资源的初始化任务。 #include iostream #include thread #include mutexusing namespace std;void init(){cout Initialing...endl; }void worker(once_flag* flag){call_once(*flag,init); }int main(){once_flag flag;thread t1(worker,flag);thread t2(worker,flag);thread t3(worker,flag);t1.join();t2.join();t3.join();return 0; }Initialing...无法确定具体是哪一个线程会执行init 3. 并发 #includeiostream #includecmath #includechrono #includevector #includethreadusing namespace std;static const int MAX 10e8; static double sum 0;void worker(int min,int max){for(int i min; imax; i){sum sqrt(i);} }void serial_task(int min,int max){auto start_time chrono::steady_clock::now();sum 0;worker(0,MAX);auto end_time chrono::steady_clock::now();auto ms chrono::duration_castchrono::microseconds(end_time-start_time).count();cout Serail task finish, ms ms consumed, Result: sum endl; }void concurrent_task(int min, int max){auto start_time chrono::steady_clock::now();unsigned concurrent_count thread::hardware_concurrency();cout hardware_concurrency: concurrent_count endl;vectorthread threads;min 0;sum 0;for(int t 0; t concurrent_count; t){int range max / concurrent_count * (t 1);threads.push_back(thread(worker,min,range));min range 1;}for(int i 0; i threads.size(); i){threads[i].join();}auto end_time chrono::steady_clock::now();auto ms chrono::duration_castchrono::milliseconds(end_time-start_time).count();cout Concurrent task finish, ms ms consumed, Result: sum endl;}int main(){serial_task(0, MAX);concurrent_task(0, MAX);return 0; }定义了一个串行任务函数serial_task它接受两个参数min和max。在这个函数中首先记录任务开始的时间然后将sum重置为0接着调用worker函数来进行计算计算的范围是从0到MAX。接着记录任务结束的时间计算任务执行时间并输出计算结果。 接着定义了一个并行任务函数concurrent_task它也接受两个参数min和max。在这个函数中首先记录任务开始的时间然后通过thread::hardware_concurrency()函数获取系统的并发线程数并输出到控制台。接着定义一个线程数组threads并用循环创建多个线程来执行worker函数每个线程计算一个范围内的数的平方根并累加到sum变量中。最后等待所有线程执行完毕记录任务结束的时间计算任务执行时间并输出计算结果。 Serail task finish, 6655 ms consumed, Result: 2.10819e13 hardware_concurrency: 8 Concurrent task finish, 5232 ms consumed, Result: 2.88206e12 #在这里并行的速度并没有比串行快多少而且计算的结果还是错的处理器在进行计算的时候高速缓存会参与其中例如数据的读和写。而高速缓存和系统主存Memory是有可能存在不一致的。即某个结果计算后保存在处理器的高速缓存中了但是没有同步到主存中此时这个值对于其他处理器就是不可见的。 事情还远不止这么简单。我们对于全局变量值的修改sum sqrt(i);这条语句它并非是原子的。它其实是很多条指令的组合才能完成。假设在某个设备上这条语句通过下面这几个步骤来完成。它们的时序可能如下所示 竞争条件与临界区 当多个进程或者线程同时访问共享数据时只要有一个任务会修改数据那么就可能会发生问题。此时结果依赖于这些任务执行的相对时间这种场景称为竞争条件race condition。 访问共享数据的代码片段称之为临界区critical section。具体到上面这个示例临界区就是读写sum变量的地方。 4. 互斥和锁 mutex 开发并发系统的目的主要是为了提升性能将任务分散到多个线程然后在不同的处理器上同时执行。这些分散开来的线程通常会包含两类任务 独立的对于划分给自己的数据的处理对于处理结果的汇总 其中第1项任务因为每个线程是独立的不存在竞争条件的问题。而第2项任务由于所有线程都可能往总结果例如上面的sum变量汇总这就需要做保护了。在某一个具体的时刻只应当有一个线程更新总结果即保证每个线程对于共享数据的访问是“互斥”的。mutex 就提供了这样的功能。 APIC标准说明mutexC11提供基本互斥设施timed_mutexC11提供互斥设施带有超时功能recursive_mutexC11提供能被同一线程递归锁定的互斥设施recursive_timed_mutexC11提供能被同一线程递归锁定的互斥设施带有超时功能shared_timed_mutexC14提供共享互斥设施并带有超时功能shared_mutexC17提供共享互斥设施 方法说明lock锁定互斥体如果不可用则阻塞try_lock尝试锁定互斥体如果不可用直接返回unlock解锁互斥体 这三个方法提供了基础的锁定和解除锁定的功能。使用lock意味着有很强的意愿一定要获取到互斥体而使用try_lock则是进行一次尝试。这意味着如果失败了你通常还有其他的路径可以走。 在这些基础功能之上其他的类分别在下面三个方面进行了扩展 超时timed_mutexrecursive_timed_mutexshared_timed_mutex的名称都带有timed这意味着它们都支持超时功能。它们都提供了try_lock_for和try_lock_until方法这两个方法分别可以指定超时的时间长度和时间点。如果在超时的时间范围内没有能获取到锁则直接返回不再继续等待。可重入recursive_mutex和recursive_timed_mutex的名称都带有recursive。可重入或者叫做可递归是指在同一个线程中同一把锁可以锁定多次。这就避免了一些不必要的死锁。共享shared_timed_mutex和shared_mutex提供了共享功能。对于这类互斥体实际上是提供了两把锁一把是共享锁一把是互斥锁。一旦某个线程获取了互斥锁任何其他线程都无法再获取互斥锁和共享锁但是如果有某个线程获取到了共享锁其他线程无法再获取到互斥锁但是还有获取到共享锁。这里互斥锁的使用和其他的互斥体接口和功能一样。而共享锁可以同时被多个线程同时获取到使用共享锁的接口见下面的表格。共享锁通常用在读者写者模型上。 使用共享锁的接口如下 方法说明lock_shared获取互斥体的共享锁如果无法获取则阻塞try_lock_shared尝试获取共享锁如果不可用直接返回unlock_shared解锁共享锁 在访问共享数据之前加锁访问完成之后解锁在多线程中使用带锁的版本 #include chrono #include cmath #include iostream #include mutex #include thread #include vectorusing namespace std;static const int MAX 10e8; static double sum 0;static mutex exclusive;void concurrent_worker(int min, int max) {for (int i min; i max; i) {exclusive.lock();sum sqrt(i);exclusive.unlock();} }void worker(int min, int max) {for (int i min; i max; i) {double sqrt_i sqrt(i);// 使用互斥锁保护对 sum 的访问lock_guardmutex lock(sum_mutex);sum sqrt_i;} }void concurrent_task(int min, int max) {auto start_time chrono::steady_clock::now();unsigned concurrent_count thread::hardware_concurrency();cout hardware_concurrency: concurrent_count endl;vectorthread threads;min 0;sum 0;for (int t 0; t concurrent_count; t) {int range max / concurrent_count * (t 1);threads.push_back(thread(concurrent_worker, min, range));min range 1;}for (int i 0; i threads.size(); i) {threads[i].join();}auto end_time chrono::steady_clock::now();auto ms chrono::duration_castchrono::milliseconds(end_time - start_time).count();cout Concurrent task finish, ms ms consumed, Result: sum endl; }int main() {concurrent_task(0, MAX);return 0; } Serail task finish, 26665 ms consumed, Result: 2.10819e13 (1) hardware_concurrency: 8 Concurrent task finish, 156722 ms consumed, Result: 2.10819e13 (2) hardware_concurrency: 8 Concurrent task finish, 167880 ms consumed, Result: 2.10819e13结果是对了但是我们却发现这个版本比原先单线程的版本性能还要差很多。这是因为加锁和解锁是有代价的这里计算最耗时的地方在锁里面每次只能有一个线程串行执行相比于单线程模型它不但是串行的还增加了锁的负担因此就更慢了。 于是我们改造concurrent_worker像下面这样 // 08_improved_mutex_lock.cppvoid concurrent_worker(int min, int max) {double tmp_sum 0;for (int i min; i max; i) {tmp_sum sqrt(i); // ①}exclusive.lock(); // ②sum tmp_sum;exclusive.unlock(); }这段代码的改变在于两处 通过一个局部变量保存当前线程的处理结果在汇总总结过的时候进行锁保护 hardware_concurrency: 8 Concurrent task finish, 1304 ms consumed, Result: 2.10819e13用锁的粒度granularity来描述锁的范围。细粒度fine-grained是指锁保护较小的范围粗粒度coarse-grained是指锁保护较大的范围。出于性能的考虑我们应该保证锁的粒度尽可能的细。并且不应该在获取锁的范围内执行耗时的操作例如执行IO。如果是耗时的运算也应该尽可能的移到锁的外面。 死锁 #include iostream #include mutex #include set #include threadusing namespace std;class Account { public:Account(string name, double money): mName(name), mMoney(money) {};public:void changeMoney(double amount) {mMoney amount;}string getName() {return mName;}double getMoney() {return mMoney;}mutex* getLock() {return mMoneyLock;}private:string mName;double mMoney;mutex mMoneyLock; };class Bank { public:void addAccount(Account* account) {mAccounts.insert(account);}bool transferMoney(Account* accountA, Account* accountB, double amount) {lock_guardmutex guardA(*accountA-getLock());lock_guardmutex guardB(*accountB-getLock());if (amount accountA-getMoney()) {return false;}accountA-changeMoney(-amount);accountB-changeMoney(amount);return true;}double totalMoney() const {double sum 0;for (auto a : mAccounts) {sum a-getMoney();}return sum;}private:setAccount* mAccounts; };void randomTransfer(Bank* bank, Account* accountA, Account* accountB) {while(true) {double randomMoney ((double)rand() / RAND_MAX) * 100;if (bank-transferMoney(accountA, accountB, randomMoney)) {cout Transfer randomMoney from accountA-getName() to accountB-getName() , Bank totalMoney: bank-totalMoney() endl;} else {cout Transfer failed, accountA-getName() has only $ accountA-getMoney() , but randomMoney required endl;}} }int main() {Account a(Paul, 100);Account b(Moira, 100);Bank aBank;aBank.addAccount(a);aBank.addAccount(b);thread t1(randomTransfer, aBank, a, b);thread t2(randomTransfer, aBank, b, a);t1.join();t2.join();return 0; }这两个线程可能会同时获取其中一个账号的锁然后又想获取另外一个账号的锁此时就发生了死锁。如下图所示 当然发生死锁的原因远不止上面这一种情况。如果两个线程互相join就可能发生死锁。还有在一个线程中对一个不可重入的互斥体例如mutex而非recursive_mutex多次加锁也会死锁。 修改 #include iostream #include mutex #include set #include threadusing namespace std;class Account { public:Account(string name, double money): mName(name), mMoney(money) {};public:void changeMoney(double amount) {mMoney amount;}string getName() {return mName;}double getMoney() {return mMoney;}mutex* getLock() {return mMoneyLock;}private:string mName;double mMoney;mutex mMoneyLock; };class Bank { public:void addAccount(Account* account) {mAccounts.insert(account);}bool transferMoney(Account* accountA, Account* accountB, double amount) {// lock(*accountA-getLock(), *accountB-getLock());// lock_guard lockA(*accountA-getLock(), adopt_lock);// lock_guard lockB(*accountB-getLock(), adopt_lock);scoped_lock lockAll(*accountA-getLock(), *accountB-getLock());if (amount accountA-getMoney()) {return false;}accountA-changeMoney(-amount);accountB-changeMoney(amount);return true;}double totalMoney() const {double sum 0;for (auto a : mAccounts) {sum a-getMoney();}return sum;}private:setAccount* mAccounts; };mutex sCoutLock; void randomTransfer(Bank* bank, Account* accountA, Account* accountB) {while(true) {double randomMoney ((double)rand() / RAND_MAX) * 100;if (bank-transferMoney(accountA, accountB, randomMoney)) {sCoutLock.lock();cout Transfer randomMoney from accountA-getName() to accountB-getName() , Bank totalMoney: bank-totalMoney() endl;sCoutLock.unlock();} else {sCoutLock.lock();cout Transfer failed, accountA-getName() has only accountA-getMoney() , but randomMoney required endl;sCoutLock.unlock();}} }int main() {Account a(Paul, 100);Account b(Moira, 100);Bank aBank;aBank.addAccount(a);aBank.addAccount(b);thread t1(randomTransfer, aBank, a, b);thread t2(randomTransfer, aBank, b, a);t1.join();t2.join();return 0; }C17 或更早版本的标准并且编译器不支持 C17 的 mutex 头文件中的 scoped_lock所以要指定g以c17标准编译 g -stdc17 10_improved_bank_transfer.cpp -o 10test -pthread通用锁定算法 APIC标准说明lockC11锁定指定的互斥体若任何一个不可用则阻塞try_lockC11试图通过重复调用 try_lock 获得互斥体的所有权 RAII std::mutex 是 C11 中最基本的 mutex 类通过实例化 std::mutex 可以创建互斥量 而通过其成员函数 lock() 可以进行上锁unlock() 可以进行解锁。 但是在实际编写代码的过程中最好不去直接调用成员函数 因为调用成员函数就需要在每个临界区的出口处调用 unlock()当然还包括异常。 这时候 C11 还为互斥量提供了一个 RAII 语法的模板类 std::lock_guard。 RAII 在不失代码简洁性的同时很好的保证了代码的异常安全性。 在 RAII 用法下对于临界区的互斥量的创建只需要在作用域的开始部分例如 #include iostream #include mutex #include threadint v 1;void critical_section(int change_v) {static std::mutex mtx;std::lock_guardstd::mutex lock(mtx);// 执行竞争操作v change_v;// 离开此作用域后 mtx 会被释放 }int main() {std::thread t1(critical_section, 2), t2(critical_section, 3);t1.join();t2.join();std::cout v std::endl;return 0; }情况1不加锁 233 情况2 2 3 3 情况3 3 2 3由于 C 保证了所有栈对象在生命周期结束时会被销毁所以这样的代码也是异常安全的。 无论 critical_section() 正常返回、还是在中途抛出异常都会引发堆栈回退也就自动调用了 unlock()。 而 std::unique_lock 则是相对于 std::lock_guard 出现的std::unique_lock 更加灵活 std::unique_lock 的对象会以独占所有权没有其他的 unique_lock 对象同时拥有某个 mutex 对象的所有权 的方式管理 mutex 对象上的上锁和解锁的操作。所以在并发编程中推荐使用 std::unique_lock。 std::lock_guard 不能显式的调用 lock 和 unlock 而 std::unique_lock 可以在声明后的任意位置调用 可以缩小锁的作用范围提供更高的并发度。 如果你用到了条件变量 std::condition_variable::wait 则必须使用 std::unique_lock 作为参数。 例如 #include iostream #include mutex #include threadusing namespace std; int v 1; void critical_section(int change_v){static mutex mtx;unique_lockmutex lock(mtx);v change_v;cout1: v endl;//释放锁lock.unlock();// 在此期间任何人都可以抢夺 v 的持有权// 开始另一组竞争操作再次加锁lock.lock();v 1;cout2: v endl; }int main(){thread t1(critical_section,2),t2(critical_section,3);t1.join();t2.join();return 0; }情况1 1:3 2:4 1:2 2:3 情况2 1:2 2:3 1:3 2:4
http://www.zqtcl.cn/news/438362/

相关文章:

  • 网站用什么切版商城网站怎么建
  • 设计网站公司多少钱wordpress获取所有标签
  • 怎么看一个网站是哪个公司做的电子商务网站设计与规划
  • 邯郸哪里做网站优化网站建设如何排版
  • 济南网站建设设计制作公司找人做网站价格
  • 阿里网站年费续费怎么做分录大型的网站开发
  • 中山做网站费用广西壮族自治区住房和建设厅网站
  • vs2015做网站如何添加控件建设网站计划 ppt
  • 简述网站设计流程贵阳小程序开发软件公司
  • 营销网站建设的原则设计网站页面要注意什么
  • 上海怎么做网站国外网站 设计
  • 开发公司土地评估费计入土地价款优化搜狐的培训
  • 网站建设佰首选金手指三360怎么免费建网站
  • 网站万能密码修复苏州市建设中心网站
  • 如何搭建php网站网站制作的前期主要是做好什么工作
  • 站酷设计网站官网站不能正常显示出现后台代码
  • 网站域名改版微信公众号免费开通
  • 代网站建设如何对网站进行爬虫
  • 做公司+网站建设价格低网站两边广告代码
  • 服务器上怎做网站提升网页优化排名
  • 上海网站推广模板景德镇网站开发
  • 艺术风格网站成都软件开发公司排行榜
  • 搭建个人网站赚钱网站开发应该注意什么
  • 医药招商网站建设做招聘网站都需要什么手续
  • 通州网站建设电话外贸订单网站推广
  • 余江县建设局网站福州外包加工网
  • 为网站网站做推广加强网络安全建设
  • dedecms 模版网站wordpress 10万并发
  • 衡阳企业网站排名优化深圳网站建设 联雅网络
  • 厦门网站建设案例做网站需要买多大空间