Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/thread/stop callback"

From cppreference.com
< cpp‎ | thread
m (langlinks)
m (fmt, capitalized 1st letter, .)
 
(One intermediate revision by one user not shown)
Line 1: Line 1:
 
{{cpp/title|stop_callback}}
 
{{cpp/title|stop_callback}}
 
{{cpp/thread/stop_callback/navbar}}
 
{{cpp/thread/stop_callback/navbar}}
{{ddcl | header=stop_token | since=c++20 |
+
{{ddcl|header=stop_token|since=c++20|
 
template< class Callback >
 
template< class Callback >
 
class stop_callback;
 
class stop_callback;
Line 20: Line 20:
 
===Member types===
 
===Member types===
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc hitem | Type | Definition }}
+
{{dsc hitem|Type|Definition}}
{{dsc | {{tt|callback_type}} | {{tt|Callback}}}}
+
{{dsc|{{tt|callback_type}}|{{tt|Callback}}}}
 
{{dsc end}}
 
{{dsc end}}
  
 
===Member functions===
 
===Member functions===
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc inc | cpp/thread/stop_callback/dsc constructor}}
+
{{dsc inc|cpp/thread/stop_callback/dsc constructor}}
{{dsc inc | cpp/thread/stop_callback/dsc destructor}}
+
{{dsc inc|cpp/thread/stop_callback/dsc destructor}}
{{dsc inc | cpp/thread/stop_callback/dsc operator{{=}}}}
+
{{dsc inc|cpp/thread/stop_callback/dsc operator{{=}}}}
 
{{dsc end}}
 
{{dsc end}}
  
Line 34: Line 34:
  
 
===Example===
 
===Example===
{{example |
+
{{example
| code=
+
|code=
 
#include <chrono>
 
#include <chrono>
 
#include <condition_variable>
 
#include <condition_variable>
Line 45: Line 45:
 
using namespace std::chrono_literals;
 
using namespace std::chrono_literals;
  
// Use a helper class for atomic std::cout streaming
+
// Use a helper class for atomic std::cout streaming.
 
class Writer
 
class Writer
 
{
 
{
std::ostringstream buffer;
+
    std::ostringstream buffer;
 
public:
 
public:
~Writer() {
+
    ~Writer()
std::cout << buffer.str();
+
    {
}
+
        std::cout << buffer.str();
Writer& operator<<(auto input) {
+
    }
buffer << input;
+
    Writer& operator<<(auto input)
return *this;
+
    {
}
+
        buffer << input;
 +
        return *this;
 +
    }
 
};
 
};
  
 
int main()
 
int main()
 
{
 
{
// A worker thread
+
    // A worker thread.
// It will wait until it is requested to stop.
+
    // It will wait until it is requested to stop.
std::jthread worker([] (std::stop_token stoken) {
+
    std::jthread worker([] (std::stop_token stoken)
Writer() << "Worker thread's id: " << std::this_thread::get_id() << '\n';
+
    {
std::mutex mutex;
+
        Writer() << "Worker thread's id: " << std::this_thread::get_id() << '\n';
std::unique_lock lock(mutex);
+
        std::mutex mutex;
std::condition_variable_any().wait(lock, stoken,
+
        std::unique_lock lock(mutex);
[&stoken] { return stoken.stop_requested(); });
+
        std::condition_variable_any().wait(lock, stoken,
});
+
            [&stoken] { return stoken.stop_requested(); });
 +
    });
  
// Register a stop callback on the worker thread.
+
    // Register a stop callback on the worker thread.
std::stop_callback callback(worker.get_stop_token(), [] {
+
    std::stop_callback callback(worker.get_stop_token(), []
Writer() << "Stop callback executed by thread: "
+
    {
<< std::this_thread::get_id() << '\n';
+
        Writer() << "Stop callback executed by thread: "
});
+
            << std::this_thread::get_id() << '\n';
 +
    });
  
// stop_callback objects can be destroyed prematurely to prevent execution
+
    // Stop_callback objects can be destroyed prematurely to prevent execution.
{
+
    {
std::stop_callback scoped_callback(worker.get_stop_token(), [] {
+
        std::stop_callback scoped_callback(worker.get_stop_token(), []
// This will not be executed.
+
        {
Writer() << "Scoped stop callback executed by thread: "
+
            // This will not be executed.
<< std::this_thread::get_id() << '\n';
+
            Writer() << "Scoped stop callback executed by thread: "
});
+
                << std::this_thread::get_id() << '\n';
}
+
        });
 +
    }
  
// Demonstrate which thread executes the stop_callback and when.
+
    // Demonstrate which thread executes the stop_callback and when.
// Define a stopper function
+
    // Define a stopper function.
auto stopper_func = [&worker] {
+
    auto stopper_func = [&worker]
if(worker.request_stop())
+
    {
Writer() << "Stop request executed by thread: "
+
        if (worker.request_stop())
<< std::this_thread::get_id() << '\n';
+
            Writer() << "Stop request executed by thread: "
else
+
                << std::this_thread::get_id() << '\n';
Writer() << "Stop request not executed by thread: "
+
        else
<< std::this_thread::get_id() << '\n';
+
            Writer() << "Stop request not executed by thread: "
};
+
                << std::this_thread::get_id() << '\n';
 +
    };
  
// Let multiple threads compete for stopping the worker thread
+
    // Let multiple threads compete for stopping the worker thread.
std::jthread stopper1(stopper_func);
+
    std::jthread stopper1(stopper_func);
std::jthread stopper2(stopper_func);
+
    std::jthread stopper2(stopper_func);
stopper1.join();
+
    stopper1.join();
stopper2.join();
+
    stopper2.join();
  
// After a stop has already been requested,
+
    // After a stop has already been requested,
// a new stop_callback executes immediately.
+
    // a new stop_callback executes immediately.
Writer() << "Main thread: " << std::this_thread::get_id() << '\n';
+
    Writer() << "Main thread: " << std::this_thread::get_id() << '\n';
std::stop_callback callback_after_stop(worker.get_stop_token(), [] {
+
    std::stop_callback callback_after_stop(worker.get_stop_token(), []
Writer() << "Stop callback executed by thread: "
+
    {
<< std::this_thread::get_id() << '\n';
+
        Writer() << "Stop callback executed by thread: "
});
+
            << std::this_thread::get_id() << '\n';
 +
    });
 
}
 
}
| p=true
+
|p=true
| output=
+
|output=
 
Worker thread's id: 140460265039616
 
Worker thread's id: 140460265039616
 
Stop callback executed by thread: 140460256646912
 
Stop callback executed by thread: 140460256646912

Latest revision as of 10:38, 23 October 2023

 
 
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
(C++11)
Cooperative cancellation
(C++20)
stop_callback
(C++20)
Mutual exclusion
(C++11)
Generic lock management
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
Condition variables
(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 <stop_token>
template< class Callback >
class stop_callback;
(since C++20)

The stop_callback class template provides an RAII object type that registers a callback function for an associated std::stop_token object, such that the callback function will be invoked when the std::stop_token's associated std::stop_source is requested to stop.

Callback functions registered via stop_callback's constructor are invoked either in the same thread that successfully invokes request_stop() for a std::stop_source of the stop_callback's associated std::stop_token; or if stop has already been requested prior to the constructor's registration, then the callback is invoked in the thread constructing the stop_callback.

More than one stop_callback can be created for the same std::stop_token, from the same or different threads concurrently. No guarantee is provided for the order in which they will be executed, but they will be invoked synchronously; except for stop_callback(s) constructed after stop has already been requested for the std::stop_token, as described previously.

If an invocation of a callback exits via an exception then std::terminate is called.

std::stop_callback is not CopyConstructible, CopyAssignable, MoveConstructible, nor MoveAssignable.

The template param Callback type must be both invocable and destructible. Any return value is ignored.

Contents

[edit] Member types

Type Definition
callback_type Callback

[edit] Member functions

constructs new stop_callback object
(public member function) [edit]
destructs the stop_callback object
(public member function) [edit]
operator=
[deleted]
stop_callback is not assignable
(public member function) [edit]

[edit] Deduction guides

[edit] Example

#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <sstream>
#include <thread>
 
using namespace std::chrono_literals;
 
// Use a helper class for atomic std::cout streaming.
class Writer
{
    std::ostringstream buffer;
public:
    ~Writer()
    {
        std::cout << buffer.str();
    }
    Writer& operator<<(auto input)
    {
        buffer << input;
        return *this;
    }
};
 
int main()
{
    // A worker thread.
    // It will wait until it is requested to stop.
    std::jthread worker([] (std::stop_token stoken)
    {
        Writer() << "Worker thread's id: " << std::this_thread::get_id() << '\n';
        std::mutex mutex;
        std::unique_lock lock(mutex);
        std::condition_variable_any().wait(lock, stoken,
            [&stoken] { return stoken.stop_requested(); });
    });
 
    // Register a stop callback on the worker thread.
    std::stop_callback callback(worker.get_stop_token(), []
    {
        Writer() << "Stop callback executed by thread: "
            << std::this_thread::get_id() << '\n';
    });
 
    // Stop_callback objects can be destroyed prematurely to prevent execution.
    {
        std::stop_callback scoped_callback(worker.get_stop_token(), []
        {
            // This will not be executed.
            Writer() << "Scoped stop callback executed by thread: "
                << std::this_thread::get_id() << '\n';
        });
    }
 
    // Demonstrate which thread executes the stop_callback and when.
    // Define a stopper function.
    auto stopper_func = [&worker]
    {
        if (worker.request_stop())
            Writer() << "Stop request executed by thread: "
                << std::this_thread::get_id() << '\n';
        else
            Writer() << "Stop request not executed by thread: "
                << std::this_thread::get_id() << '\n';
    };
 
    // Let multiple threads compete for stopping the worker thread.
    std::jthread stopper1(stopper_func);
    std::jthread stopper2(stopper_func);
    stopper1.join();
    stopper2.join();
 
    // After a stop has already been requested,
    // a new stop_callback executes immediately.
    Writer() << "Main thread: " << std::this_thread::get_id() << '\n';
    std::stop_callback callback_after_stop(worker.get_stop_token(), []
    {
        Writer() << "Stop callback executed by thread: "
            << std::this_thread::get_id() << '\n';
    });
}

Possible output:

Worker thread's id: 140460265039616
Stop callback executed by thread: 140460256646912
Stop request executed by thread: 140460256646912
Stop request not executed by thread: 140460248254208
Main thread: 140460265043776
Stop callback executed by thread: 140460265043776