The use of std::condition_variable in C++11 __c++

Source: Internet
Author: User
Tags mutex

<condition_variable> is a header file in the C + + standard library, which defines the classes and methods used in the C++11 standard to represent conditional variables in concurrent programming.

Conditional variable is a kind of control structure in concurrent programming. When multiple threads access a shared resource (or a critical section), not only do you need to use mutexes to achieve exclusive access to avoid concurrent errors (called competitive hazards), you need to verify that a particular condition is set up after acquiring a mutex into a critical area:

(1) If this condition is not met, the thread that owns the mutex should release the mutex, block itself and hang to the thread queue of the (suspend) condition variable

(2) If this condition is met, the thread that owns the mutex accesses the shared resource within the critical zone, notifies (notify) the thread that is blocking in the thread queue of the condition variable, and the notified thread must reapply the lock for the mutex.

The implementation of the newly added conditional variable in the standard library of C++11 is exactly consistent with the implementation semantics of pthread. When using conditional variables for concurrency control, the individual threads that block on a condition variable at some point should indicate the same mutex when the wait operation is invoked, when the condition variable is bound to the mutex, or the behavior of the program is undefined. The condition variable must be used in conjunction with the mutex, on the grounds that the program needs to determine whether a condition (condition or predict) is tenable, and that the condition can be arbitrarily complex.

A thread leaving a critical section is unblocked (unblock) with notify operations when each thread on a condition variable, according to fairness (fairness), these threads should have equal access to the mutex, and should not allow a thread to be starved to death (starvation) with a mutex that is always difficult to obtain And more than any other thread that later went to the critical section (that is, basically FIFO). One way to do this is to call the Notify_all thread to hold the mutex until all the threads unblocked from the condition variable have been suspended (suspend) to the mutex lock, and then the Notify_all thread is released to release the mutex. Mutexes generally have a relatively perfect blocking thread scheduling algorithm, generally according to the thread priority scheduling, the same priority in accordance with FIFO scheduling.

A thread that initiates a notify does not need to have a mutex. The thread that is about to leave the critical section is to release the mutex first or the notify operation to suspend the blocking of the thread on the condition variable. The surface can be seen in both of these sequences. However, it is generally recommended that you first notify the operation and then unlock the mutex. This is because it benefits the fairness of the above, while avoiding the possible precedence inversion in the reverse order. This first notify is pessimistic (pessimization) because the notified (notified) thread is immediately blocked, waiting for the notification (notifying) thread to release the mutex. Many implementations (especially Pthreads implementations), in order to avoid such "haste and wait" situations, move the notified thread waiting on the thread queue of the condition variable directly to the thread queue of the mutex, without waking the threads.

The conditional variables are introduced in the c++11, and the related contents are in <condition_variable>. Here mainly introduces the Std::condition_variable class.

Conditional variable std::condition_variable is used for communication between multithreading, which can block one or both threads. Std::condition_variable need to be used in conjunction with Std::unique_lock. The std::condition_variable effect is equivalent to wrapping a function of the pthread_cond_* () series in the Pthread library.

When a Std::condition_variable object's wait function is invoked, it uses Std::unique_lock (via Std::mutex) to lock the current thread. The current thread is blocked until another thread invokes the notification function on the same Std::condition_variable object to wake the current thread.

Std::condition_variable objects typically use std::unique_lock<std::mutex> to wait, and if you need to use a different lockable type, you can use the Std::condition_ Variable_any class.

member functions for the Std::condition_variable class:

(1), constructors: Only default constructors are supported, and copies, assignments, and moves (move) are disabled.

(2), wait: The current thread will be blocked after the call to (), until another thread calls Notify_* to wake the current thread, and when the thread is blocked, the function automatically calls the Std::mutex unlock () release lock, Enables other threads that are blocked to compete in the lock to continue executing. Once the line is notified (notify, usually another thread calls notify_* to wake up the current thread), the Wait () function also automatically invokes the lock () of Std::mutex. Wait is divided into two types, which are unconditionally blocked and conditionally blocked.

Unconditionally blocked: The current thread should have completed lock on unique_lock<mutex> lck before calling this function. All threads that use the same condition variable must use the same unique_lock<mutex> in the wait function. The wait function will automatically call Lck.unlock () to unlock the mutex, causing other threads that are blocked in the mutex to resume execution. When the current thread that is blocked with this function is awakened by the notification (notified, a function that calls the Notify_* series via another thread), the wait () function resumes execution and automatically calls Lck.lock () to lock the mutex.

Conditional blocking: The wait function sets a predicate (predicate) that only blocks the current thread if the pred condition is false, and is unblocked only if Pred is true after receiving notification from another thread. Therefore, it is equivalent to while (!pred ()) Wait (LCK).

(3), Wait_for: Similar to wait (), only wait_for can specify a time period, the thread will be blocked until the current thread receives a notification or a specified time elapses. Once you have timed out or received a notification from another thread, WAIT_FOR returns, and the rest of the steps are similar to wait.

(4), Wait_until: Similar to wait_for, only wait_until can specify a point in time, the thread will be blocked until the current thread receives a notification or a specified point in time elapses. Once you have timed out or received a notification from another thread, Wait_until returns, and the remaining processing steps are similar to wait.

(5), Notify_all: Wakes all wait threads, if there is no waiting thread, then the function does nothing.

(6), Notify_one: Wake up a wait thread, if there is no waiting thread, then the function does nothing, if there are more than one waiting thread, wake a thread is indeterminate (unspecified).

The condition changes with false arousal, so it is necessary to check if the condition is satisfied after the thread is awakened. Whether the Notify_one or Notify_all are similar to emitting a pulse signal, if the call to wait is not awakened after the notify, the receiver also needs to check that the condition is satisfied before it is used by waiting.

The Std::condition_variable_any class is the same as the std::condition_variable usage, except that the Std::condition_variable_ Any of the wait functions can accept any lockable parameter, and std::condition_variable can only accept parameters of the std::unique_lock<std::mutex> type. Std::notify_all_at_thread_exit function: When the thread that calls the function exits, all threads waiting on the COND condition variable will be notified.

STD::CONDITION_VARIABLE:A condition variable is a object able to blocks the calling thread until to notified. It uses a unique_lock (over a mutex) to lock "thread" when one of It, functions is called. The thread remains blocked until woken up by another thread this calls a notification function on the same condition_varia Ble object. Objects of type condition_variable always use unique_lock<mutex>-wait:for an alternative D of lockable type, Condition_variable_any.

The Condition_variable class is a synchronization primitive so can be used to blocks a thread, or multiple threads at the Same time, until another thread both modifies a shared variable (the condition), and notifies the condition_variable.

The thread that intends to modify the variable has to: (1), acquire a std::mutex (typically via Std::lock_guard), (2), perform The modification while the lock is held (3), execute Notify_one or Notify_all on the std::condition_variable (The lock Doe s not need to is held for notification).

Any thread this is intends to std::condition_variable has to: (1), acquire a std::unique_lock<std::mutex> Same mutex as used to protect the shared variable; (2), execute wait, wait_for, or Wait_until. The wait operations atomically the mutex and suspend the execution of the thread; (3), when the condition variable i s notified, a timeout expires, or a spurious wake up occurs,the thread are awakened, and the mutex is atomically reacquired . The thread should then check the condition and resume waiting if the wake up is spurious.

Std::condition_variable works with std::unique_lock<std::mutex>; This restriction allows to maximal efficiency on some platforms. Std::condition_variable_any provides a condition variable that works with any Basiclockable object, such as Std::shared_lo Ck.

Here is the copy of the Std::condition_variable test code from other articles, the details can refer to the corresponding reference:

#include "condition_variable.hpp" #include <iostream> #include <chrono> #include <thread> #include <mutex> #include <condition_variable> #include <string> namespace Condition_variable_ {//////////// reference:http://www.cplusplus.com/reference/
Condition_variable/condition_variable/std::mutex MTX;
Std::condition_variable CV;

BOOL ready = FALSE;
	static void print_id (int id) {std::unique_lock<std::mutex> lck (MTX);
	while (!ready) cv.wait (LCK);

... std::cout << "thread" << ID << ' \ n ';}
	static void Go () {std::unique_lock<std::mutex> lck (MTX);
	Ready = true;
Cv.notify_all ();
	int Test_condition_variable_1 () {std::thread threads[10];

	Spawn threads:for (int i = 0; i<10; ++i) threads[i] = Std::thread (print_id, i);
	Std::cout << "Ten Threads Ready to race...\n";                       Go ();

	Go! for (auto& th:threads)Th.join ();
return 0; }///////////////////////////////////////////////////////////////////////////reference:http://www.cplusplus.com /reference/condition_variable/condition_variable/wait///Condition_variable::wait:wait until notified,//the
Execution of the current thread (which shall have locked Lck ' s mutexes) is blocked until. At the moment of blocking the thread, the function automatically calls Lck.unlock (), allowing other locked threads to C
Ontinue. If pred is specified, the function only blocks if Pred returns FALSE,//and notifications can only unblock the thread
When it becomes true (which are specially useful to check against spurious wake-up).
Std::mutex mtx2;

Std::condition_variable Cv2;
int cargo = 0;

static bool Shipment_available () {return cargo!= 0;}
		static void consume (int n) {for (int i = 0; i<n; ++i) {std::unique_lock<std::mutex> lck (MTX2);
		Cv2.wait (Lck, shipment_available); Consume:std::cout << Cargo << ' \ n ';
		Cargo = 0;
	Std::cout << "* * *:" << cargo << Std::endl;

	an int test_condition_variable_wait () {Std::thread consumer_thread (consume, 10); Produce items when needed:for (int i = 0; i<10; ++i) {while (shipment_available ()) Std::this_thread::yield ()
		;
		Std::unique_lock<std::mutex> lck (MTX2);
		Cargo = i + 1;
	Cv2.notify_one ();

	} consumer_thread.join ();
return 0; }/////////////////////////////////////////////////////////////////////////////reference:http:// www.cplusplus.com/reference/condition_variable/condition_variable/wait_for///Condition_variable::wait_for:wait For timeout or until notified//the execution of the current thread (which shall, have locked ' s mutex) is lck blocked
Ng Rel_time,//or until notified (if the latter happens a). At the moment of blocking the thread, the function automatically calls Lck.unlock (),//allowing other locked threads t
o continue.
Std::condition_variable Cv3; int value;
	static void Read_value () {std::cin >> value;
Cv3.notify_one ();
	int test_condition_variable_wait_for () {std::cout << "Please, enter an integer (I'll be printing dots): \ n";

	Std::thread th (Read_value);
	Std::mutex MTX;
	Std::unique_lock<std::mutex> lck (MTX); while (Cv3.wait_for (Lck, Std::chrono::seconds (1)) = = Std::cv_status::timeout) {std::cout << '. ' << std::end
	L

	} std::cout << "you entered:" << value << ' \ n ';

	Th.join ();
return 0; }////////////////////////////////////////////////////////////////////reference:http://www.cplusplus.com/ reference/condition_variable/condition_variable/notify_one///Condition_variable::notify_one:notify One, Unblocks
One of the threads currently waiting for this condition.
If no threads are waiting, the function does nothing.
If more than one, it's unspecified which of the threads is selected.
Std::mutex mtx4;

Std::condition_variable Produce4, Consume4;   int Cargo4 = 0;  Shared value by producers and consumers Static void Consumer4 () {std::unique_lock<std::mutex> lck (mtx4);
	while (Cargo4 = = 0) consume4.wait (LCK);
	Std::cout << Cargo4 << ' \ n ';
	Cargo4 = 0;
Produce4.notify_one ();
	static void producer (int id) {std::unique_lock<std::mutex> lck (mtx4);
	while (Cargo4!= 0) produce4.wait (LCK);
	Cargo4 = ID;
Consume4.notify_one ();
	int Test_condition_variable_notify_one () {std::thread consumers[10], producers[10];
		Spawn consumers and producers:for (int i = 0; i<10; ++i) {Consumers[i] = Std::thread (CONSUMER4);
	Producers[i] = Std::thread (producer, i + 1);
		}//join them back:for (int i = 0; i<10; ++i) {producers[i].join ();
	Consumers[i].join ();
return 0; }///////////////////////////////////////////////////////////////reference:http://www.cplusplus.com/reference/ condition_variable/condition_variable/notify_all///Condition_variable::notify_all:notify all, Unblocks all threadsCurrently waiting for this condition.
If no threads are waiting, the function does nothing.
Std::mutex mtx5;
Std::condition_variable cv5;

BOOL ready5 = false;
	static void print_id5 (int id) {std::unique_lock<std::mutex> lck (MTX5);
	while (!ready5) cv5.wait (LCK);

... std::cout << "thread" << ID << ' \ n ';}
	static void Go5 () {std::unique_lock<std::mutex> lck (MTX5);
	Ready5 = true;
Cv5.notify_all ();
	int Test_condition_variable_notify_all () {std::thread threads[10];

	Spawn threads:for (int i = 0; i<10; ++i) threads[i] = Std::thread (PRINT_ID5, i);
	Std::cout << "Ten Threads Ready to race...\n";                       Go5 ();

	Go!

	for (auto& th:threads) th.join ();
return 0; }//////////////////////////////////////////////////////////////reference:http://en.cppreference.com/w/cpp/
Thread/condition_variable Std::mutex m;
Std::condition_variable cv6;
std::string data;
BOOL Ready6 = false;

BOOL processed = FALSE;static void Worker_thread () {//wait until main () sends data std::unique_lock<std::mutex> LK (m);

	Cv6.wait (LK, []{return ready6;});
	After the wait, we own the lock.
	Std::cout << "Worker thread is processing data\n";

	Data + + "after processing";
	Send data back to main () processed = true;

	Std::cout << "Worker thread signals data processing completed\n"; Manual unlocking is do before notifying, to avoid waking up//The waiting thread only to block again (
	E for details) lk.unlock ();
Cv6.notify_one ();

	int test_condition_variable_2 () {std::thread worker (Worker_thread);
	data = "Example data";
		Send data to the worker thread {std::lock_guard<std::mutex> lk (m);
		Ready6 = true;
	Std::cout << "main () signals data ready for processing\n";

	} cv6.notify_one ();
		Wait for the worker {std::unique_lock<std::mutex> lk (m);
	Cv6.wait (LK, []{return processed;}); } std::cout << "Back in Main" (), DATA = "<< data << ' \ n ';

	Worker.join ();
return 0;
 }//Namespace Condition_variable_

GitHub: Https://github.com/fengbingchun/Messy_Test

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.