std::thread
Normal threads are the traditional way to create concurrent threads in C++.
They are created explicitly using the std::thread class. The programmer is responsible for managing the thread's lifecycle, including starting, joining, and destroying the thread.
Normal threads also do not return a value, so the programmer must use some other mechanism, such as shared memory or inter-thread communication, to communicate the results of the thread's execution.
std::async
Asynchronous threads are a newer way to create concurrent threads in C++. They are created implicitly using the std::async function. The std::async function returns a std::future object,
which can be used to get the result of the thread's execution.
Asynchronous threads are automatically managed by the system, so the programmer does not need to worry about starting, joining, or destroying the thread.
using namespace std;
int double_number(int n) {
return n * 2;
}
int main() {
// Create an asynchronous thread that calls the double_number function
future<int> future = async(double_number, 10);
// Do some other work while the asynchronous thread is running
cout << "Doing some other work..." << endl;
// Get the result of the asynchronous thread
int result = future.get();
cout << "The result is: " << result << endl;
return 0;
}
which can be used to get the result of the thread's execution.
Asynchronous threads are automatically managed by the system, so the programmer does not need to worry about starting, joining, or destroying the thread.
Asych thread pool example 1
- Avoid blocking the main thread
- Queue tasks
- Perform tasks independently
#include <iostream>
#include <vector>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <deque>
class ThreadPool {
public:
ThreadPool(size_t numThreads);
~ThreadPool();
void enqueue(std::function<void()> task);
private:
// Thread pool worker function
void workerThread();
// Data members
std::vector<std::thread> workers;
std::deque<std::function<void()>> tasks;
std::mutex queueMutex;
std::condition_variable condition;
bool stop;
};
// Constructor: Create worker threads
ThreadPool::ThreadPool(size_t numThreads) : stop(false) {
for (size_t i = 0; i < numThreads; ++i) {
workers.emplace_back([this] { workerThread(); });
}
}
// Destructor: Stop worker threads
ThreadPool::~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queueMutex);
stop = true;
}
condition.notify_all();
for (std::thread& worker : workers) {
worker.join();
}
}
// Worker thread function
void ThreadPool::workerThread() {
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(queueMutex);
condition.wait(lock, [this] { return stop || !tasks.empty(); });
if (stop && tasks.empty()) {
return;
}
task = std::move(tasks.front());
tasks.pop_front();
}
task(); // Perform the task
}
}
// Enqueue a task for the thread pool to execute asynchronously
void ThreadPool::enqueue(std::function<void()> task) {
{
std::unique_lock<std::mutex> lock(queueMutex);
tasks.emplace_back(std::move(task));
}
condition.notify_one(); // Notify conditional wait when tasks available in queue
}
// Example usage
void exampleTask(int arg) {
std::cout << "Task executed with argument: " << arg << " by Thread " << std::this_thread::get_id() << std::endl;
}
int main() {
const size_t numThreads = 4;
ThreadPool threadPool(numThreads);
// Enqueue tasks
for (int i = 0; i < 8; ++i) {
threadPool.enqueue([i] { exampleTask(i); });
}
// Continue with other tasks in the main thread without waiting for the pool
for (int i = 0; i < 5; ++i) {
std::cout << "Main thread task: " << i << std::endl;
}
// Sleep for a while to allow threads to execute tasks
std::this_thread::sleep_for(std::chrono::seconds(2));
return 0;
}
Asych thread pool example 2
- Avoid blocking the main thread
- Queue tasks
- Perform tasks independently
- Limit the maximum number of concurrently running threads to 10.
- Other new tasks will be queued until a free thread is available
#include <iostream>
#include <vector>
#include <future>
#include <deque>
#include <functional>
#include <chrono>
#include <thread>
class ThreadPool {
public:
ThreadPool(size_t maxThreads);
~ThreadPool();
void enqueue(std::function<void()> task);
private:
// Thread pool worker function
void workerThread();
// Data members
std::deque<std::packaged_task<void()>> tasks;
std::vector<std::future<void>> futures;
size_t maxThreads;
size_t activeThreads;
};
// Constructor: Create worker threads
ThreadPool::ThreadPool(size_t maxThreads) : maxThreads(maxThreads), activeThreads(0) {
for (size_t i = 0; i < maxThreads; ++i) {
futures.emplace_back(std::async(std::launch::async, [this] { workerThread(); }));
}
}
// Destructor: Stop worker threads
ThreadPool::~ThreadPool() {
// No need to explicitly stop threads when using std::async
}
// Worker thread function
void ThreadPool::workerThread() {
while (true) {
std::packaged_task<void()> task;
{
std::unique_lock<std::mutex> lock(queueMutex);
condition.wait(lock, [this] { return tasks.empty(); });
if (tasks.empty()) {
return;
}
task = std::move(tasks.front());
tasks.pop_front();
++activeThreads;
}
task();
{
std::unique_lock<std::mutex> lock(queueMutex);
--activeThreads;
}
}
}
// Enqueue a task for the thread pool to execute asynchronously
void ThreadPool::enqueue(std::function<void()> task) {
{
std::unique_lock<std::mutex> lock(queueMutex);
tasks.emplace_back(std::packaged_task<void()>(std::move(task)));
}
condition.notify_one();
}
// Example usage
void exampleTask(int arg) {
std::cout << "Task executed with argument: " << arg << " by Thread " << std::this_thread::get_id() << std::endl;
}
int main() {
const size_t maxThreads = 10;
ThreadPool threadPool(maxThreads);
// Enqueue tasks
for (int i = 0; i < 15; ++i) {
threadPool.enqueue([i] { exampleTask(i); });
}
// Continue with other tasks in the main thread without waiting for the pool
for (int i = 0; i < 5; ++i) {
std::cout << "Main thread task: " << i << std::endl;
}
// Sleep for a while to allow threads to execute tasks
std::this_thread::sleep_for(std::chrono::seconds(2));
return 0;
}
No comments:
Post a Comment