C++相关闲碎记录(18)

1、strftime()的转换指示器

C++相关闲碎记录(18)_第1张图片

#include 
#include 
#include 
#include 
#include 
#include 
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& tpC = use_facet>(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& tpG = use_facet>(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、用于字符分类的辅助函数

C++相关闲碎记录(18)_第2张图片

 3、随机数

#include 
#include 
#include 
#include 

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 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 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 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

4、分布

C++相关闲碎记录(18)_第3张图片

#include 
#include 
#include 
#include 
#include 

template 
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 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
====

5、async()

#include 
#include 
#include 
#include 
#include 
#include 
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 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

6、shared_future()

#include 
#include 
#include 
#include 
#include 
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 f)
{
    try {
        // wait for number of characters to print
        int num = f.get();  // get result of queryNumber()

        for (int i=0; i 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

7、thread()

#include 
#include 
#include 
#include 
#include 
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 id(10,1000);
        for (int i=0; i

8、promise()

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

void doSomething (std::promise& 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 p;
        // create a future to process the outcome
        std::future 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 

C++相关闲碎记录(18)_第4张图片

 9、packaged_task<>操作

 10、unique_lock

std::unique_lock 是 C++ 标准库中的一个锁管理工具,它提供了对互斥量(std::mutex)的更灵活的管理和使用方式。std::unique_lock 具有比 std::lock_guard 更多的特性,例如支持延迟锁定和手动解锁,使其在一些复杂的情境下更为适用。

 (1)构造函数
std::unique_lock lock(mutex);

传递mutex互斥量,unique_lock对象会立即锁定互斥量。

(2)延迟锁定

std::lock_guard 不同,std::unique_lock 可以在构造时选择是否立即锁定互斥量。可以通过构造函数的第二个参数 std::defer_lock 来实现延迟锁定。

std::unique_lock lock(mutex, std::defer_lock);
//这里互斥量并未锁定
...
lock.lock();  //手动锁定互斥量
(3)手动解锁

std::lock_guard 不同,std::unique_lock 允许在需要的时候手动解锁互斥量,然后再次锁定。

std::unique_lock lock(mutex);
//...
lock.unlock();  //手动解锁
//...
lock.lock();  //手动锁定
(4)条件变量

std::unique_lock 提供了与条件变量一起使用的特性,可以在等待条件满足时自动释放锁,以及在条件不满足时重新获取锁。

std::unique_lock lock(mutex);
cv.wait(lock, [](){return condition;});
(5)锁定多个互斥量

std::unique_lock 允许锁定多个互斥量,以防止死锁。可以在构造函数中传递多个互斥量,并使用 std::lock 来避免死锁。

std::mutex mutex1, mutex2;
std::unique_lock lock1(mutex1, std::defer_lock);
std::unique_lock lock2(mutex2, std::defer_lock);
std::lock(lock1, lock2);

C++相关闲碎记录(18)_第5张图片

11、mutex和lock

C++相关闲碎记录(18)_第6张图片C++相关闲碎记录(18)_第7张图片

 12、condition variable

#include 
#include 
#include 
#include 
#include 
#include 

std::queue 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 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 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。

13、atomic

C++相关闲碎记录(18)_第8张图片

 

你可能感兴趣的:(c++)