Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/thread/condition variable"

From cppreference.com
< cpp‎ | thread
(Undo revision 146659 by Sancho (talk))
Line 1: Line 1:
#include <iostream>
+
{{cpp/title|condition_variable}}
//zadanie1
+
{{cpp/thread/condition_variable/navbar}}
// Funkcja pomocnicza fun_aux, dla trzech podanych liczb, ma zwracać wartość największą.
+
{{ddcl | header=condition_variable | since=c++11 | 1=
float fun_aux(float a, float b, float c){
+
class condition_variable;
    if(a >= b && a >= c){
+
}}
        return a;
+
    }else if(b >= c && b >= a){
+
        return b;
+
    }else{
+
        return c;
+
    }
+
    // 2 wersja -> trzeba dodać #include <cmath> na początku
+
    // return std::max(std::max(a,b),c);
+
}
+
  
// Zdefiniuj funkcję fun_arr, która w parametrze przyjmie dwie tablice (o podanej wyżej specyfikacji) oraz wskaźnik na pewną dodatkową funkcję fun_aux.
+
The {{tt|condition_variable}} class is a synchronization primitive used with a {{lc|std::mutex}} to block one or more threads until another thread both modifies a shared variable (the ''condition'') and notifies the {{tt|condition_variable}}.
void fun_arr(float *in_arr, float *out_arr, int N, float (*f)(float, float, float)){
+
    for(int i = 0; i < N; i++){
+
        // Funkcja fun_arr z każdych trzech sąsiadujących elementów (o indeksach {3i, 3i+1, 3i+2}) z pierwszej tablicy ma obliczyć, za pomocą fun_aux, pojedynczą wartość i wstawić ją do drugiej tablicy w element o indeksie i.
+
        out_arr[i] = f(in_arr[i*3], in_arr[i*3+1], in_arr[i*3+2]);
+
    }
+
}
+
  
int main() {
+
The thread that intends to modify the shared variable must:
//    Dane są dwie tablice liczb zmiennoprzecinkowych o długościach: (1) 3*N oraz (2) N, gdzie N jest liczbą naturalną.
+
# Acquire a {{tt|std::mutex}} (typically via {{lc|std::lock_guard}})
    int N = 4;
+
# Modify the shared variable while the lock is owned
    float *in_array = new float[3*N];
+
# Call {{lc|notify_one}} or {{lc|notify_all}} on the {{tt|std::condition_variable}} (can be done after releasing the lock)
    float *out_array = new float[N];
+
Even if the shared variable is atomic, it must be modified while owning the mutex to correctly publish the modification to the waiting thread.
    // W funkcji głównej stwórz przykładowe dynamiczne tablice (1) i (2) spełniające warunki z początku zadania
+
    // lepiej by podać konkretne wartości arr[i] =5.0; lub arr[0]=2.3; itd
+
    for(int i = 0; i<3*N; i++){
+
        std::cin>>in_array[i];
+
    }
+
    // i wykorzystując funkcje fun_arr i fun_aux, uzupełnij tablicę wyjściową (2)
+
    fun_arr(in_array, out_array, N, fun_aux);
+
    // Wypisz na ekranie jej wartości
+
    for(int i = 0; i<N; i++){
+
        std::cout<<out_array[i]<<" ";
+
    }
+
    // Zadbaj o właściwe zarządzanie pamięcią dynamiczną.
+
    delete[] in_array;
+
    delete[] out_array;
+
  
    return 0;
+
Any thread that intends to wait on a {{tt|std::condition_variable}} must:
}
+
# Acquire a {{c|std::unique_lock<std::mutex>}} on the mutex used to protect the shared variable
 +
# Do one of the following:
 +
:# Check the condition, in case it was already updated and notified
 +
:# Call {{lc|wait}}, {{lc|wait_for}}, or {{lc|wait_until}} on the {{tt|std::condition_variable}} (atomically releases the mutex and suspends thread execution until the condition variable is notified, a timeout expires, or a [[enwiki:Spurious_wakeup|spurious wakeup]] occurs, then atomically acquires the mutex before returning)
 +
:# Check the condition and resume waiting if not satisfied
 +
:: or:
 +
:# Use the predicated overload of {{lc|wait}}, {{lc|wait_for}}, and {{lc|wait_until}}, which performs the same three steps
  
#include <iostream>
+
{{tt|std::condition_variable}} works only with {{c|std::unique_lock<std::mutex>}}, which allows for maximal efficiency on some platforms. {{lc|std::condition_variable_any}} provides a condition variable that works with any {{named req|BasicLockable}} object, such as  {{lc|std::shared_lock}}.
//zadanie2
+
void *get_element(void **arr, int n, int x, int y, size_t sizen) {
+
    if (x < 0 or y < 0 or y > n - 1) {
+
        return nullptr;
+
    }
+
    if (x > n - y - 1) {
+
        return nullptr;
+
    }
+
  
 +
Condition variables permit concurrent invocation of the {{lc|wait}}, {{lc|wait_for}}, {{lc|wait_until}}, {{lc|notify_one}} and {{lc|notify_all}} member functions.
  
    char **pom = (char **) arr;
+
The class {{tt|std::condition_variable}} is a {{named req|StandardLayoutType}}. It is not {{named req|CopyConstructible}}, {{named req|MoveConstructible}}, {{named req|CopyAssignable}}, or {{named req|MoveAssignable}}.
    return (void *) &pom[y][sizen * x];
+
  
}
+
===Member types===
 +
{{dsc begin}}
 +
{{dsc hitem | Member type | Definition}}
 +
{{dsc | {{tt|native_handle_type}} | ''implementation-defined''}}
 +
{{dsc end}}
  
int main() {
+
===Member functions===
    const int n = 5;
+
{{dsc begin}}
 +
{{dsc inc | cpp/thread/condition_variable/dsc constructor | condition_variable}}
 +
{{dsc inc | cpp/thread/condition_variable/dsc destructor | condition_variable}}
 +
{{dsc inc | cpp/thread/condition_variable/dsc operator{{=}} | condition_variable}}
  
    // ALOKACJA TABLICY
+
{{dsc h2 | Notification}}
    int **arr = new int *[n];
+
{{dsc inc | cpp/thread/condition_variable/dsc notify_one | condition_variable}}
 +
{{dsc inc | cpp/thread/condition_variable/dsc notify_all | condition_variable}}
  
    int index = 0;
+
{{dsc h2 | Waiting}}
 
+
{{dsc inc | cpp/thread/condition_variable/dsc wait | condition_variable}}
    for (int i = 0; i < n; i++) {
+
{{dsc inc | cpp/thread/condition_variable/dsc wait_for | condition_variable}}
        arr[i] = new int[n - i];
+
{{dsc inc | cpp/thread/condition_variable/dsc wait_until | condition_variable}}
        for (int j = 0; j < n - i; j++) {
+
            arr[i][j] = index++;
+
        }
+
    }
+
 
+
 
+
    // WYPISYWANIE TABLICY
+
    for (int i = 0; i < n; i++) {
+
        for (int j = 0; j < n - i; j++) {
+
            std::cout << arr[i][j] << "\t";
+
        }
+
        std::cout << std::endl;
+
    }
+
 
+
    std::cout << std::endl;
+
 
+
 
+
    // DZIAŁANIE FUNKCJI get_element
+
    int *pom = (int *) get_element((void **) arr, n, 2, 1, sizeof(int));
+
    if (pom != nullptr) {
+
        std::cout << *pom << std::endl;
+
    } else {
+
        std::cout << "nullptr" << std::endl;
+
    }
+
 
+
    // DEALOKACJA TABLICY
+
    for (int i = 0; i < n; i++) {
+
        delete[] arr[i];
+
    }
+
    delete[] arr;
+
 
+
}
+
  
 +
{{dsc h2 | Native handle}}
 +
{{dsc inc | cpp/thread/condition_variable/dsc native handle | condition_variable}}
 +
{{dsc end}}
  
 +
===Example===
 +
{{example| {{tt|condition_variable}} is used in combination with a {{lc|std::mutex}} to facilitate inter-thread communication.
 +
|code=
 
#include <iostream>
 
#include <iostream>
#include <math.h>
+
#include <string>
//ZADANIE 3
+
#include <thread>
void arr_fun(float* vecs_beg, float* vecs_end, float* res_beg, float (*fun)(float, float)){
+
#include <mutex>
    float* curr_vec = vecs_beg;
+
#include <condition_variable>
    while(curr_vec != vecs_end){
+
        *res_beg = fun(*curr_vec, *(curr_vec+1));
+
        curr_vec += 2;
+
        res_beg++;
+
    }
+
}
+
  
float vec_len(float a, float b){
+
std::mutex m;
    return std::sqrt(a*a + b*b);
+
std::condition_variable cv;
}
+
std::string data;
 +
bool ready = false;
 +
bool processed = false;
  
int main(){
+
void worker_thread()
 +
{
 +
    // Wait until main() sends data
 +
    std::unique_lock lk(m);
 +
    cv.wait(lk, []{return ready;});
  
     float vecs[] = { 1.0, 1.0,
+
     // after the wait, we own the lock.
                    2.0, 1.0,
+
    std::cout << "Worker thread is processing data\n";
                    1.0, 3.0,
+
    data += " after processing";
                    3.0, 1.0, };
+
  
     float res[4];
+
     // Send data back to main()
     arr_fun(vecs, vecs+8, res, vec_len);
+
    processed = true;
 +
     std::cout << "Worker thread signals data processing completed\n";
 
      
 
      
     for(int i=0; i<4; i++){
+
     // Manual unlocking is done before notifying, to avoid waking up
        std::cout << res[i] << '\t';
+
    // the waiting thread only to block again (see notify_one for details)
     }
+
     lk.unlock();
    std::cout << '\n';
+
     cv.notify_one();
 
+
     return 0;
+
 
}
 
}
  
 +
int main()
 +
{
 +
    std::thread worker(worker_thread);
  
 
+
     data = "Example data";
#include <iostream>
+
     // send data to the worker thread
//zadanie4
+
     {
int main() {
+
         std::lock_guard lk(m);
     // napisz program, który przyjmie od użytkownika liczbę całkowitą n
+
         ready = true;
    int n;
+
         std::cout << "main() signals data ready for processing\n";
    std::cin>>n;
+
     // utwórz dynamiczną tablicę liczb całkowitych arr i wypełnij ją wartościami od użytkownika większymi od 0
+
     // liczby te reprezentują liczbę elementów dla kolejnych wierszy nieregularnej tablicy dwuwymiarowej arr2d
+
    int *arr = new int[n];
+
    for(int i=0; i<n; i++){
+
         std::cin>>arr[i];
+
    }
+
    // utwórz dynamiczną n-elementową tablicę wskaźników na tablice liczb zmiennoprzecinkowych arr2d
+
    float **arr2d = new float * [n];
+
    // każdemu wskaźnikowi zarezerwuj pamięć zgodnie z korespondującą indeksowo wartością tablicy arr
+
    for(int i=0; i<n; i++){
+
        int size = arr[i];
+
         arr2d[i] = new float[size];
+
         // lub w pętli może być tylko
+
        // arr2d[i] = new float[arr[i]];
+
    }
+
    // wypełnij wszystkie tablice liczbami zmiennoprzecinkowymi pobranymi od użytkownika
+
    for(int i = 0; i<n; i++){
+
        for(int j = 0; j<arr[i]; j++){
+
            std::cin>>arr2d[i][j];
+
        }
+
    }
+
    // utwórz dynamiczną n-elementową tablicę liczb zmiennoprzecinkowych result,
+
    float *result = new float[n];
+
    // której elementami są sumy elementów poszczególnych wierszy tablicy arr2d
+
    for(int i = 0; i<n; i++){
+
        result[i] = 0;
+
        for(int j = 0; j<arr[i]; j++){
+
            result[i]+=arr2d[i][j];
+
        }
+
    }
+
    // wyświetl jej zawartość
+
    for(int i=0; i<n; i++){
+
        std::cout<<result[i]<<" ";
+
 
     }
 
     }
 +
    cv.notify_one();
  
     // dealokacja pamięci
+
     // wait for the worker
     for(int i = 0; i<n; i++){
+
     {
         delete[] arr2d[i];
+
        std::unique_lock lk(m);
 +
         cv.wait(lk, []{return processed;});
 
     }
 
     }
     delete[] arr2d;
+
     std::cout << "Back in main(), data = " << data << '\n';
    delete[] result;
+
    delete[] arr;
+
    return 0;
+
}
+
  
#include <iostream>
+
     worker.join();
#include <cstdlib>
+
//zadanie5
+
float count_float(int a, int b){
+
     float float_number;
+
    if(a<b){
+
        float_number = a*1.0+b/10.0;
+
    }else{
+
        float_number = b*1.0+a/10.0;
+
    }
+
    return float_number;
+
 
}
 
}
 +
| output=
 +
main() signals data ready for processing
 +
Worker thread is processing data
 +
Worker thread signals data processing completed
 +
Back in main(), data = Example data after processing
 +
}}
  
int main() {
+
===See also===
    srand( time( NULL ) );
+
{{dsc begin}}
    int n, m;
+
{{dsc inc | cpp/thread/dsc condition_variable_any}}
    std::cin>>n>>m;
+
{{dsc inc | cpp/thread/dsc mutex}}
    int **arr2d = new int*[n];
+
{{dsc inc | cpp/thread/dsc lock_guard}}
    for(int i=0; i<n; i++){
+
{{dsc inc | cpp/thread/dsc unique_lock}}
        arr2d[i] = new int[2*m];
+
{{dsc end}}
        for(int j=0; j<m*2; j++){
+
            arr2d[i][j] = std::rand()%10;
+
        }
+
    }
+
    float **arr2d_2 = new float*[n];
+
    for(int i=0; i<n; i++){
+
        arr2d_2[i] = new float[m];
+
        for(int j=0; j<m; j++){
+
            arr2d_2[i][j] = count_float(arr2d[i][2*j], arr2d[i][2*j+1]);
+
        }
+
    }
+
    for(int i=0; i<n; i++){
+
        for(int j=0; j<2*m; j++){
+
            std::cout<<arr2d[i][j]<<" ";
+
        }
+
        std::cout<<std::endl;
+
    }
+
    for(int i=0; i<n; i++){
+
        for(int j=0; j<m; j++){
+
            std::cout<<arr2d_2[i][j]<<" ";
+
        }
+
        std::cout<<std::endl;
+
    }
+
    for(int i=0; i<n; i++){
+
        delete[] arr2d[i];
+
        delete[] arr2d_2[i];
+
  
    }
+
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}
    delete[] arr2d;
+
    delete[] arr2d_2;
+
 
+
    return 0;
+
}
+
 
+
#include <stdio.h>
+
#include <cstring>
+
#include <iostream>
+
//zadanie6
+
void parse(char** usersData, char** results, int n){
+
    for (int i = 0; i < n; i++){
+
        char* nickname = strtok(usersData[i], ";");
+
        char* games = strtok(NULL, ";");
+
        char* wins = strtok(NULL, ";");
+
        char* elims = strtok(NULL, ";");
+
 
+
        int gamesInt = atoi(games);
+
        int winsInt = atoi(wins);
+
        int elimsInt = atoi(elims);
+
 
+
        int temp = gamesInt + winsInt + elimsInt;
+
 
+
        char* result = new char[100];
+
        sprintf(result, "%s %d", nickname, temp);
+
        results[i] = result;
+
    }
+
}
+
 
+
 
+
int main(){
+
    int n;
+
    scanf("%d", &n);
+
 
+
    char** usersData = new char*[n];
+
 
+
    for (int i = 0; i < n; i++){
+
        char* data = new char[100];
+
        scanf("%s", data);
+
        usersData[i] = data;
+
    }
+
 
+
    char** results = new char*[n];
+
 
+
    parse(usersData, results, n);
+
 
+
    for (int i = 0; i < n; i++){
+
        printf("%s\n", results[i]);
+
    }
+
 
+
    return 0;
+
}
+
 
+
// 4
+
// MystiqueHero;1365;6890;15210
+
// Frizz;5400;6200;11000
+
// Ziemniak;9965;11000;73000
+
// Evel00na;10;10;90
+
 
+
 
+
#include <stdio.h>
+
#include <cstring>
+
#include <iostream>
+
//zadanie7
+
int group_plates(char** plates, char** results, int n){
+
    int m = 0;
+
    for (int i = 0; i < n; i++){
+
        char* plate = plates[i];
+
        char* reg = strtok(plate, " ");
+
        char* num = strtok(NULL, " ");
+
        bool grouped = false;
+
        for (int j = 0; j < m; j++){
+
            char* result = results[j];
+
            int res_reg_len;
+
            if (result[2] == ' '){
+
                res_reg_len = 2;
+
            } else {
+
                res_reg_len = 3;
+
            }
+
            if (strncmp(result, reg, res_reg_len) == 0){
+
                strcat(results[j], " ");
+
                strcat(results[j], num);
+
                grouped = true;
+
                break;
+
            }
+
        }
+
        if (!grouped){
+
            char* new_result = new char[1024];
+
            strcpy(new_result, reg);
+
            strcat(new_result, " ");
+
            strcat(new_result, num);
+
            results[m] = new_result;
+
            m++;
+
        }
+
    }
+
    return m;
+
}
+
 
+
int main(){
+
    int n;
+
    n = 5;
+
    char** plates = new char*[n]{new char[100]{"LRY 1234"}, new char[100]{"LU 87654"}, new char[100]{"WA 1234"}, new char[100]{"LRY 888"}, new char[100]{"LU 999"}};
+
 
+
    char** results = new char*[n];
+
 
+
    int m = group_plates(plates, results, n);
+
 
+
    for (int i = 0; i < m; i++){
+
        std::cout << results[i] << '\n';
+
    }
+
 
+
    return 0;
+
}
+
 
+
// 5
+
// LRY 1234
+
// LU 87654
+
// WA 1234
+
// LRY 888
+
// LU 999
+
 
+
 
+
 
+
 
+
#include <iostream>
+
#include <cmath>
+
//zadanie8
+
void sort_fun(float *arr, int n){
+
    for(int i = 0; i<n-1; i++){
+
        for(int j = 0; j<n-1-i; j++){
+
            if(arr[2*j] > arr[2*(j+1)] or (arr[2*j] == arr[2*(j+1)] and arr[2*j]<arr[2*j+2])){
+
                float tmpf = arr[2*j];
+
                float tmpr = arr[2*j+1];
+
                arr[2*j] = arr[2*j+2];
+
                arr[2*j+1] = arr[2*j+3];
+
                arr[2*j+2] = tmpf;
+
                arr[2*j+3] = tmpr;
+
            }
+
        }
+
    }
+
}
+
 
+
int main() {
+
    int N = 3;
+
    float *arr = new float [2*N];
+
    for(int i = 0; i<2*N; i++){
+
        std::cin>>arr[i];
+
    }
+
    sort_fun(arr,N);
+
    float R,F,x,y;
+
    for(int i = 0; i<N; i++){
+
        R = arr[2*i];
+
        F = arr[2*i+1];
+
        x = R*cos(F);
+
        y = R*sin(F);
+
        std::cout<<x<<" "<<y<<std::endl;
+
 
+
    }
+
    delete[] arr;
+
    return 0;
+
}
+

Revision as of 04:02, 20 January 2023

 
 
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
(C++11)
Generic lock management
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
Condition variables
condition_variable
(C++11)
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
(C++11)
Safe Reclamation
(C++26)
Hazard Pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11)(deprecated in C++20)
(C++11)(deprecated in C++20)
Memory ordering
Free functions for atomic operations
Free functions for atomic flags
 
 
Defined in header <condition_variable>
class condition_variable;
(since C++11)

The condition_variable class is a synchronization primitive used with a std::mutex to block one or more threads until another thread both modifies a shared variable (the condition) and notifies the condition_variable.

The thread that intends to modify the shared variable must:

  1. Acquire a std::mutex (typically via std::lock_guard)
  2. Modify the shared variable while the lock is owned
  3. Call notify_one or notify_all on the std::condition_variable (can be done after releasing the lock)

Even if the shared variable is atomic, it must be modified while owning the mutex to correctly publish the modification to the waiting thread.

Any thread that intends to wait on a std::condition_variable must:

  1. Acquire a std::unique_lock<std::mutex> on the mutex used to protect the shared variable
  2. Do one of the following:
  1. Check the condition, in case it was already updated and notified
  2. Call wait, wait_for, or wait_until on the std::condition_variable (atomically releases the mutex and suspends thread execution until the condition variable is notified, a timeout expires, or a spurious wakeup occurs, then atomically acquires the mutex before returning)
  3. Check the condition and resume waiting if not satisfied
or:
  1. Use the predicated overload of wait, wait_for, and wait_until, which performs the same three steps

std::condition_variable works only with std::unique_lock<std::mutex>, which allows for maximal efficiency on some platforms. std::condition_variable_any provides a condition variable that works with any BasicLockable object, such as std::shared_lock.

Condition variables permit concurrent invocation of the wait, wait_for, wait_until, notify_one and notify_all member functions.

The class std::condition_variable is a StandardLayoutType. It is not CopyConstructible, MoveConstructible, CopyAssignable, or MoveAssignable.

Contents

Member types

Member type Definition
native_handle_type implementation-defined

Member functions

constructs the object
(public member function) [edit]
destructs the object
(public member function) [edit]
operator=
[deleted]
not copy-assignable
(public member function) [edit]
Notification
notifies one waiting thread
(public member function) [edit]
notifies all waiting threads
(public member function) [edit]
Waiting
blocks the current thread until the condition variable is awakened
(public member function) [edit]
blocks the current thread until the condition variable is awakened or after the specified timeout duration
(public member function) [edit]
blocks the current thread until the condition variable is awakened or until specified time point has been reached
(public member function) [edit]
Native handle
returns the native handle
(public member function) [edit]

Example

condition_variable is used in combination with a std::mutex to facilitate inter-thread communication.

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
 
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
 
void worker_thread()
{
    // Wait until main() sends data
    std::unique_lock lk(m);
    cv.wait(lk, []{return ready;});
 
    // 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 done before notifying, to avoid waking up
    // the waiting thread only to block again (see notify_one for details)
    lk.unlock();
    cv.notify_one();
}
 
int main()
{
    std::thread worker(worker_thread);
 
    data = "Example data";
    // send data to the worker thread
    {
        std::lock_guard lk(m);
        ready = true;
        std::cout << "main() signals data ready for processing\n";
    }
    cv.notify_one();
 
    // wait for the worker
    {
        std::unique_lock lk(m);
        cv.wait(lk, []{return processed;});
    }
    std::cout << "Back in main(), data = " << data << '\n';
 
    worker.join();
}

Output:

main() signals data ready for processing
Worker thread is processing data
Worker thread signals data processing completed
Back in main(), data = Example data after processing

See also

provides a condition variable associated with any lock type
(class) [edit]
(C++11)
provides basic mutual exclusion facility
(class) [edit]
implements a strictly scope-based mutex ownership wrapper
(class template) [edit]
implements movable mutex ownership wrapper
(class template) [edit]