#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 specifier
tpC.put (cout, cout, ' ', nowTM, 'x');
cout << endl;
// use format string:
string format = "%A %x %I%p\n"; // format: weekday date hour
tpC.put (cout, cout, ' ', nowTM,
format.c_str(), format.c_str()+format.size() );
// print local time with German locale:
#ifdef _MSC_VER
locale locG("deu_deu.1252");
#else
locale locG("de_DE");
#endif
const 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
#include <random>
#include <iostream>
#include <algorithm>
#include <vector>
int main()
{
// create default engine as source of randomness
std::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 elements
std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//...
std::shuffle (v.begin(), v.end(), // range
dre); // source of randomness
for (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
#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 values
std::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 distribution
std::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: 20087
1: 20057
2: 19878
3: 19877
4: 20005
5: 20118
6: 20063
7: 19886
8: 20003
9: 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: 26843
0: 136947
1: 26987
2: 4377
3: 258
4: 9
====
exponential_distribution:
- min(): 0
- max(): 1.79769e+308
- values: 0.48356 2.95199 0.139753 1.77765
====
0: 126327
1: 46637
2: 17118
3: 6226
4: 2337
5: 865
6: 313
7: 108
8: 38
9: 22
10: 6
11: 2
12: 1
====
gamma_distribution:
- min(): 0
- max(): 1.79769e+308
- values: 1.21066 0.558526 1.60557 0.117964
====
0: 126315
1: 46477
2: 17160
3: 6271
4: 2413
5: 866
6: 327
7: 109
8: 41
9: 12
10: 7
11: 1
12: 1
====
#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 time
for (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 exception
try {
f1.get();
f2.get();
}
catch (const exception& e) {
cout << "\nEXCEPTION: " << e.what() << endl;
}
cout << "\ndone" << endl;
}
输出:
starting 2 operations asynchronously
+..+..+...+..+.
+++++
done
#include <future>
#include <thread>
#include <iostream>
#include <exception>
#include <stdexcept>
using namespace std;
int queryNumber ()
{
// read number
cout << "read number: ";
int num;
cin >> num;
// throw exception if none
if (!cin) {
throw runtime_error("no number read");
}
return num;
}
void doSomething (char c, shared_future<int> f)
{
try {
// wait for number of characters to print
int 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 loop
auto 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 finished
f1.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 read
done
#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 program
catch (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 thread
cout << "- started fg thread " << t1.get_id() << endl;
// print other characters in other background threads
for (int i=0; i<5; ++i) {
thread t(doSomething,10,'a'+i); // print 10 chars in separate thread
cout << "- 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;
}
}
#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 outcome
std::promise<std::string> p;
// create a future to process the outcome
std::future<std::string> f(p.get_future());
// start a thread using the promise to store the outcome
std::thread t(doSomething,std::ref(p));
t.detach();
//...
// process the outcome
std::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
std::unique_lock
是 C++ 标准库中的一个锁管理工具,它提供了对互斥量(std::mutex
)的更灵活的管理和使用方式。std::unique_lock
具有比 std::lock_guard
更多的特性,例如支持延迟锁定和手动解锁,使其在一些复杂的情境下更为适用。
std::unique_lock<std::mutex> lock(mutex);
传递mutex互斥量,unique_lock对象会立即锁定互斥量。
与 std::lock_guard
不同,std::unique_lock
可以在构造时选择是否立即锁定互斥量。可以通过构造函数的第二个参数 std::defer_lock
来实现延迟锁定。
std::unique_lock<std::mutex> lock(mutex, std::defer_lock);
//这里互斥量并未锁定
...
lock.lock(); //手动锁定互斥量
与 std::lock_guard
不同,std::unique_lock
允许在需要的时候手动解锁互斥量,然后再次锁定。
std::unique_lock<std::mutex> lock(mutex);
//...
lock.unlock(); //手动解锁
//...
lock.lock(); //手动锁定
std::unique_lock
提供了与条件变量一起使用的特性,可以在等待条件满足时自动释放锁,以及在条件不满足时重新获取锁。
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, [](){return condition;});
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);
#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 queue
for (int i=0; i<6; ++i) {
{
std::lock_guard<std::mutex> lg(queueMutex);
queue.push(val+i);
} // release lock
queueCondVar.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 lock
std::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 values
auto 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。
?