1、strftime()的转换指示器
#include <locale>
#include <chrono>
#include <ctime>
#include <iostream>
#include <exception>
#include <cstdlib>
using namespace std;int main ()
{try {// query local time:auto now = chrono::system_clock::now();std::time_t t = chrono::system_clock::to_time_t(now);tm* nowTM = std::localtime(&t);// print local time with the global classic locale:locale locC;const time_put<char>& tpC = use_facet<time_put<char>>(locC);// use single conversion specifiertpC.put (cout, cout, ' ', nowTM, 'x');cout << endl;// use format string:string format = "%A %x %I%p\n"; // format: weekday date hourtpC.put (cout, cout, ' ', nowTM,format.c_str(), format.c_str()+format.size() );// print local time with German locale:
#ifdef _MSC_VERlocale locG("deu_deu.1252");
#elselocale locG("de_DE");
#endifconst time_put<char>& tpG = use_facet<time_put<char>>(locG);tpG.put (cout, cout, ' ', nowTM, 'x');cout << endl;tpG.put (cout, cout, ' ', nowTM,format.c_str(), format.c_str()+format.size() );}catch (const std::exception& e) {cerr << "Exception: " << e.what() << endl;return EXIT_FAILURE;}
}
输出:
12/19/23
Tuesday 12/19/23 04PM
Exception: locale::facet::_S_create_c_locale name not valid
2、用于字符分类的辅助函数
3、随机数
#include <random>
#include <iostream>
#include <algorithm>
#include <vector>int main()
{// create default engine as source of randomnessstd::default_random_engine dre;// use engine to generate integral numbers between 10 and 20 (both included)std::uniform_int_distribution<int> di(10,20);for (int i=0; i<20; ++i) {std::cout << di(dre) << " ";}std::cout << std::endl;// use engine to generate floating-point numbers between 10.0 and 20.0// (10.0 included, 20.0 not included)std::uniform_real_distribution<double> dr(10,20);for (int i=0; i<8; ++i) {std::cout << dr(dre) << " ";}std::cout << std::endl;// use engine to shuffle elementsstd::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };//...std::shuffle (v.begin(), v.end(), // rangedre); // source of randomnessfor (int i=0; i<v.size(); ++i) {std::cout << v[i] << " ";}std::cout << std::endl;
}
输出:
10 11 18 15 15 12 10 17 17 20 14 15 19 10 10 15 17 10 14 10
16.8677 19.3044 15.2693 16.5392 17.0119 17.622 10.4746 13.2823
5 2 8 4 3 6 7 1 9
4、分布
#include <random>
#include <map>
#include <string>
#include <iostream>
#include <iomanip>template <typename Distr, typename Eng>
void distr (Distr d, Eng e, const std::string& name)
{// print min, max and four example valuesstd::cout << name << ":" << std::endl;std::cout << "- min(): " << d.min() << std::endl; std::cout << "- max(): " << d.max() << std::endl; std::cout << "- values: " << d(e) << ' ' << d(e) << ' '<< d(e) << ' ' << d(e) << std::endl; // count the generated values (converted to integral values)std::map<long long,int> valuecounter;for (int i=0; i<200000; ++i) {valuecounter[d(e)]++;}// and print the resulting distributionstd::cout << "====" << std::endl;for (auto elem : valuecounter) {std::cout << std::setw(3) << elem.first << ": "<< elem.second << std::endl;}std::cout << "====" << std::endl;std::cout << std::endl;
}int main()
{std::knuth_b e;std::uniform_real_distribution<> ud(0, 10);distr(ud,e,"uniform_real_distribution");std::normal_distribution<> nd;distr(nd,e,"normal_distribution");std::exponential_distribution<> ed;distr(ed,e,"exponential_distribution");std::gamma_distribution<> gd;distr(gd,e,"gamma_distribution");
}
输出:
uniform_real_distribution:
- min(): 0
- max(): 10
- values: 3.83416 9.47764 1.30427 8.30965
====0: 200871: 200572: 198783: 198774: 200055: 201186: 200637: 198868: 200039: 20026
====normal_distribution:
- min(): -1.79769e+308
- max(): 1.79769e+308
- values: 0.538967 -0.140331 0.117963 -0.131724
====-4: 9-3: 245-2: 4325-1: 268430: 1369471: 269872: 43773: 2584: 9
====exponential_distribution:
- min(): 0
- max(): 1.79769e+308
- values: 0.48356 2.95199 0.139753 1.77765
====0: 1263271: 466372: 171183: 62264: 23375: 8656: 3137: 1088: 389: 2210: 611: 212: 1
====gamma_distribution:
- min(): 0
- max(): 1.79769e+308
- values: 1.21066 0.558526 1.60557 0.117964
====0: 1263151: 464772: 171603: 62714: 24135: 8666: 3277: 1098: 419: 1210: 711: 112: 1
====
5、async()
#include <future>
#include <thread>
#include <chrono>
#include <random>
#include <iostream>
#include <exception>
using namespace std;// 等待随机的时间,打印字符
void doSomething (char c)
{// random-number generator (use c as seed to get different sequences)default_random_engine dre(c);uniform_int_distribution<int> id(10,1000);// loop to print character after a random period of timefor (int i=0; i<10; ++i) {this_thread::sleep_for(chrono::milliseconds(id(dre)));cout.put(c).flush();}
}int main()
{cout << "starting 2 operations asynchronously" << endl;// start two loops in the background printing characters . or +// 多线程环境下,两个线程会被启动,当然也有可能两个都不会被启动auto f1 = async([]{ doSomething('.'); });auto f2 = async([]{ doSomething('+'); });// if at least one of the background tasks is running// 询问是否至少有一个操作未被推迟if (f1.wait_for(chrono::seconds(0)) != future_status::deferred ||f2.wait_for(chrono::seconds(0)) != future_status::deferred) {// poll until at least one of the loops finished// 询问是否至少有一个操作已经完成,如果都没有完成继续询问while (f1.wait_for(chrono::seconds(0)) != future_status::ready &&f2.wait_for(chrono::seconds(0)) != future_status::ready) {//...;// 两个线程都没有完成,切换到另外的线程this_thread::yield(); // hint to reschedule to the next thread}}cout.put('\n').flush();// wait for all loops to be finished and process any exceptiontry {f1.get();f2.get();}catch (const exception& e) {cout << "\nEXCEPTION: " << e.what() << endl;}cout << "\ndone" << endl;
}
输出:
starting 2 operations asynchronously
+..+..+...+..+.
+++++
done
6、shared_future()
#include <future>
#include <thread>
#include <iostream>
#include <exception>
#include <stdexcept>
using namespace std;int queryNumber ()
{// read numbercout << "read number: ";int num;cin >> num; // throw exception if noneif (!cin) {throw runtime_error("no number read");}return num;
}void doSomething (char c, shared_future<int> f)
{try {// wait for number of characters to printint num = f.get(); // get result of queryNumber()for (int i=0; i<num; ++i) {this_thread::sleep_for(chrono::milliseconds(100));cout.put(c).flush();}}catch (const exception& e) {cerr << "EXCEPTION in thread " << this_thread::get_id()<< ": " << e.what() << endl;}
}int main()
{try {// start one thread to query a number// 这里使用了shared_future,在下面的三个线程中多次调用,都能拿到相同的结果shared_future<int> f = async(queryNumber);// start three threads each processing this number in a loopauto f1 = async(launch::async,doSomething,'.',f);auto f2 = async(launch::async,doSomething,'+',f);auto f3 = async(launch::async,doSomething,'*',f);// wait for all loops to be finishedf1.get();f2.get();f3.get();}catch (const exception& e) {cout << "\nEXCEPTION: " << e.what() << endl;}cout << "\ndone" << endl;
}
输入:7
.+**+..+*+*.+*..*+*+.
done
输入:x
EXCEPTION in thread EXCEPTION in thread 5: EXCEPTION in thread 4: no number read
3: no number read
no number readdone
7、thread()
#include <thread>
#include <chrono>
#include <random>
#include <iostream>
#include <exception>
using namespace std;void doSomething (int num, char c)
{try {// random-number generator (use c as seed to get different sequences)default_random_engine dre(42*c);uniform_int_distribution<int> id(10,1000);for (int i=0; i<num; ++i) {this_thread::sleep_for(chrono::milliseconds(id(dre)));cout.put(c).flush();//...}}// make sure no exception leaves the thread and terminates the programcatch (const exception& e) {cerr << "THREAD-EXCEPTION (thread "<< this_thread::get_id() << "): " << e.what() << endl;}catch (...) {cerr << "THREAD-EXCEPTION (thread "<< this_thread::get_id() << ")" << endl;}
}int main()
{try {thread t1(doSomething,5,'.'); // print five dots in separate threadcout << "- started fg thread " << t1.get_id() << endl;// print other characters in other background threadsfor (int i=0; i<5; ++i) {thread t(doSomething,10,'a'+i); // print 10 chars in separate threadcout << "- detach started bg thread " << t.get_id() << endl;t.detach(); // detach thread into the background}cin.get(); // wait for any input (return)cout << "- join fg thread " << t1.get_id() << endl;t1.join(); // wait for t1 to finish}catch (const exception& e) {cerr << "EXCEPTION: " << e.what() << endl;}
}
8、promise()
#include <thread>
#include <future>
#include <iostream>
#include <string>
#include <exception>
#include <stdexcept>
#include <functional>
#include <utility>void doSomething (std::promise<std::string>& p)
{try {// read character and throw exception if 'x'std::cout << "read char ('x' for exception): ";char c = std::cin.get();if (c == 'x') {throw std::runtime_error(std::string("char ")+c+" read");}//...std::string s = std::string("char ") + c + " processed";p.set_value_at_thread_exit(std::move(s)); // store result}catch (...) {p.set_exception_at_thread_exit(std::current_exception()); // store exception}
}int main()
{try {// create a promise to store the outcomestd::promise<std::string> p;// create a future to process the outcomestd::future<std::string> f(p.get_future());// start a thread using the promise to store the outcomestd::thread t(doSomething,std::ref(p));t.detach();//...// process the outcomestd::cout << "result: " << f.get() << std::endl;}catch (const std::exception& e) {std::cerr << "EXCEPTION: " << e.what() << std::endl;}catch (...) {std::cerr << "EXCEPTION " << std::endl;}
}
输出:
result: read char ('x' for exception): 2
char 2 processed
result: read char ('x' for exception): x
EXCEPTION: char x read
9、packaged_task<>操作
10、unique_lock
std::unique_lock
是 C++ 标准库中的一个锁管理工具,它提供了对互斥量(std::mutex
)的更灵活的管理和使用方式。std::unique_lock
具有比 std::lock_guard
更多的特性,例如支持延迟锁定和手动解锁,使其在一些复杂的情境下更为适用。
(1)构造函数
std::unique_lock<std::mutex> lock(mutex);
传递mutex互斥量,unique_lock对象会立即锁定互斥量。
(2)延迟锁定
与 std::lock_guard
不同,std::unique_lock
可以在构造时选择是否立即锁定互斥量。可以通过构造函数的第二个参数 std::defer_lock
来实现延迟锁定。
std::unique_lock<std::mutex> lock(mutex, std::defer_lock);
//这里互斥量并未锁定
...
lock.lock(); //手动锁定互斥量
(3)手动解锁
与 std::lock_guard
不同,std::unique_lock
允许在需要的时候手动解锁互斥量,然后再次锁定。
std::unique_lock<std::mutex> lock(mutex);
//...
lock.unlock(); //手动解锁
//...
lock.lock(); //手动锁定
(4)条件变量
std::unique_lock
提供了与条件变量一起使用的特性,可以在等待条件满足时自动释放锁,以及在条件不满足时重新获取锁。
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, [](){return condition;});
(5)锁定多个互斥量
std::unique_lock
允许锁定多个互斥量,以防止死锁。可以在构造函数中传递多个互斥量,并使用 std::lock
来避免死锁。
std::mutex mutex1, mutex2;
std::unique_lock<std::mutex> lock1(mutex1, std::defer_lock);
std::unique_lock<std::mutex> lock2(mutex2, std::defer_lock);
std::lock(lock1, lock2);
11、mutex和lock
12、condition variable
#include <condition_variable>
#include <mutex>
#include <future>
#include <thread>
#include <iostream>
#include <queue>std::queue<int> queue;
std::mutex queueMutex;
std::condition_variable queueCondVar;void provider (int val)
{// push different values (val til val+5 with timeouts of val milliseconds into the queuefor (int i=0; i<6; ++i) {{std::lock_guard<std::mutex> lg(queueMutex);queue.push(val+i);} // release lockqueueCondVar.notify_one();std::this_thread::sleep_for(std::chrono::milliseconds(val));}
}void consumer (int num)
{// pop values if available (num identifies the consumer)while (true) {int val;{std::unique_lock<std::mutex> ul(queueMutex);queueCondVar.wait(ul,[]{ return !queue.empty(); });val = queue.front();queue.pop();} // release lockstd::cout << "consumer " << num << ": " << val << std::endl;}
}int main()
{// start three providers for values 100+, 300+, and 500+auto p1 = std::async(std::launch::async,provider,100);auto p2 = std::async(std::launch::async,provider,300);auto p3 = std::async(std::launch::async,provider,500);// start two consumers printing the valuesauto c1 = std::async(std::launch::async,consumer,1);auto c2 = std::async(std::launch::async,consumer,2);
}
所有的notify_one()和notify_all()都会被自动同步化,所以他们的调用不需要放在加锁代码块里面。所有等待某个condition variable的线程都必须使用相同的mutex,当wait()家族的某个成员被调用时,该mutex必须被unique_lock锁定,否则会发生不明确的行为。
注意:condition variable的消费者总是在“被锁住的mutex”基础上操作,只有等待函数会执行以下三个atomic步骤暂时解除mutex:1.解除mutex然后进入等待状态,2.解除因等待而造成的阻塞。3.再次锁住mutex。
13、atomic