Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use multithreaded std::call_once in C++

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly introduces how to use multithreaded std::call_once in C++, has a certain reference value, interested friends can refer to, I hope you can learn a lot after reading this article, the following let the editor take you to understand it.

In a multithreaded environment, sometimes we don't need a function to be called multiple times or some variables to be initialized multiple times, they only need to be called or initialized once. In many cases, we write the following code in order to initialize some data, which is not a problem in a single thread, but unpredictable problems occur in a multi-thread.

Bool initialized = false;void foo () {if (! initialized) {do_initialize (); / / 1 initialized = true;}}

In order to solve the problem of data inconsistency caused by resource competition in the above multithreading, most of our processing methods are to use mutexes to deal with. As long as it is protected at the ① above, the shared data is secure for concurrent access. As follows:

Bool initialized = false;std::mutex resource_mutex;void foo () {std::unique_lock lk (resource_mutex); / / all threads serialize if (! initialized) {do_initialize (); / / only initialization procedures need to be protected} initialized = true; lk.unlock (); / / do other;}

However, to ensure that the data source is initialized, each thread must wait for a mutex. To this end, others have come up with the idea of using the "double check lock mode" to improve efficiency, as follows:

Bool initialized = false;std::mutex resource_mutex;void foo () {if (! initialized) {/ / 1 std::unique_lock lk (resource_mutex); / / 2 all threads serialize if (! initialized) {do_initialize (); / / 3 only initialization procedures need to protect} initialized = true;} / / do other; / / 4}

You do not need to acquire the lock ① the first time you read the variable initialized, and you only need to acquire the lock if initialized is false. Then, when the lock is acquired, the initialized variable ② (which is part of the double check) is checked again to prevent another thread from initializing after the first check, and to let the current thread acquire the lock.

However, there are some risks in the above situation, as shown in the famous "C++ and double check locking Mode (DCLP) risks".

In this regard, the C++ Standards Committee also believes that the handling of conditional competition is very important, so the C++ standard library provides a better way to handle it: use the std::call_once function to handle it, which is defined in the header file # include. The std::call_once function can be implemented with std::once_flag: multiple threads call a function at the same time, and it can guarantee that multiple threads can only call the function once. It is defined as follows:

Struct once_flag {constexpr once_flag () noexcept; once_flag (const once_flag&) = delete; once_flag& operator= (const once_flag&) = delete;}; templatevoid call_once (once_flag& flag, Callable&& func, Args&&...) Args)

The first parameter type he accepts is std::once_flag, which is constructed with only the default constructor and cannot be copied or moved, representing an internal state of the function. The last two parameters are easy to understand, and the first one passed in is a Callable. Callable is simply callable, familiar with functions, function objects (classes that overload operator ()), std::function, and function pointers, as well as std::bind and lambda (see my previous article). The last parameter is the parameter you want to pass in. When using it, we only need to define a std::once_flag of non-local (not in the local scope of the function), and pass parameters when calling, as shown below:

# include # include # include std::once_flag flag1;void simple_do_once () {std::call_once (flag1, [] () {std::cout

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report