I'm trying to understand thread pools using boost.
I've written the following code:
#include <boost/asio/post.hpp>
#include <boost/asio/thread_pool.hpp>
#include <boost/bind/bind.hpp>
#include <iostream>
#include <chrono>
#include <thread>
class A {
public:
void asyncFunc(int i)
{
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout<< i ;
}
void beforeFunc()
{
std::cout<< "Before\n";
}
void afterFunc()
{
std::cout<< "After\n";
}
void otherFunc()
{
boost::asio::thread_pool pool(4);
for(int i = 0; i < 1000; i++)
{
beforeFunc();
boost::asio::post(pool, boost::bind(&A::asyncFunc, 3));
boost::asio::post(pool, boost::bind(&A::asyncFunc, 0));
boost::asio::post(pool, boost::bind(&A::asyncFunc, 2));
boost::asio::post(pool, boost::bind(&A::asyncFunc, 1));
afterFunc();
}
pool.join();
}
};
int main()
{
A a;
a.otherFunc();
}
But I get errors related to boost::get_pointer. (https://wandbox.org/#)
The idea would be to execute 4 asyncFuncs in parallel, but always after beforeFunc() and before afterFunc() as they will be dependent.
Do you know what I'm doing wrong in this code, or how could I achieve better what I'm trying?
You are binding non-static member functions. The first argument for non-static member function is the implicit this argument. You are passing integers there. Add the missing this:
post(pool, boost::bind(&A::asyncFunc, this, 3));
post(pool, boost::bind(&A::asyncFunc, this, 0));
post(pool, boost::bind(&A::asyncFunc, this, 2));
post(pool, boost::bind(&A::asyncFunc, this, 1));
Live On Coliru
#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <chrono>
#include <iostream>
#include <thread>
class A {
public:
void asyncFunc(int i) {
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout << i;
}
void beforeFunc() { std::cout << "Before\n"; }
void afterFunc() { std::cout << "After\n"; }
void otherFunc() {
boost::asio::thread_pool pool(4);
for (int i = 0; i < 10/*00*/; i++) {
beforeFunc();
post(pool, boost::bind(&A::asyncFunc, this, 3));
post(pool, boost::bind(&A::asyncFunc, this, 0));
post(pool, boost::bind(&A::asyncFunc, this, 2));
post(pool, boost::bind(&A::asyncFunc, this, 1));
afterFunc();
}
pool.join();
}
};
int main() {
std::cout << std::unitbuf;
A a;
a.otherFunc();
}
Prints e.g.
Before
After
Before
After
Before
After
Before
After
Before
After
Before
After
Before
After
Before
After
Before
After
Before
After
1032321030213012302130123012032131023102
Achieving What You're Trying
You won't really be done because you don't synchronize before the afterFunc(). You can do that in various ways:
C++ thread pool using boost::asio::thread_pool, why can't I reuse my threads?
Wait until A job (as starkly opposed to ALL jobs) posted to boost::asio::thread_pool completes?
Related
Why this code snippet stall?
The program intends to output firstsecondthird whereas the program stalls after firstsecond has been printed.
#include <condition_variable>
#include <mutex>
#include <thread>
#include <functional>
#include <iostream>
#include <vector>
class Foo {
public:
Foo() {
}
void first(std::function<void()> printFirst)
{
{
std::unique_lock<std::mutex> lk(mutex);
cv1.wait(lk, [this](){return 1==state;});
doing = 1;
// printFirst() outputs "first". Do not change or remove this line.
printFirst();
state = 2;
}
cv2.notify_one();
}
void second(std::function<void()> printSecond)
{
{
std::unique_lock<std::mutex> lk(mutex);
if(state !=2 )
{
if((1 == state)&&(1 != doing))
{
lk.unlock();
cv1.notify_one();
}
}
cv2.wait(lk, [this](){return 2==state;});
doing = 2;
// printSecond() outputs "second". Do not change or remove this line.
printSecond();
state = 3;
}
cv3.notify_one();
}
void third(std::function<void()> printThird)
{
{
std::unique_lock<std::mutex> lk(mutex);
if(state !=3 )
{
if((1 == state)&&(1 != doing))
{
lk.unlock();
cv1.notify_one();
}
else if((2 == state)&&(2 != doing))
{
lk.unlock();
cv2.notify_one();
}
}
cv3.wait(lk, [this](){return 3==state;});
// printThird() outputs "third". Do not change or remove this line.
printThird();
state = 3;
}
}
private:
std::condition_variable cv1;
std::condition_variable cv2;
std::condition_variable cv3;
std::mutex mutex;
int state{1};
int doing{0};
};
int main()
{
Foo foo;
std::vector<std::thread> threads;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.second([]()->void{std::cout <<"second" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.first([]()->void{std::cout <<"first" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.third([]()->void{std::cout <<"third" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::seconds(2));
for(auto itr=threads.begin(); itr!=threads.end(); itr++)
{
itr->join();
}
}
Quoted from the comments of #Igor Tandetnik.
As per the document, which says that
template void wait (unique_lock& lck, Predicate pred);
lck
A unique_lock object whose mutex object is currently locked by
this thread. All concurrent calls to wait member functions of this
object shall use the same underlying mutex object (as returned by
lck.mutex()).
So, cv2.wait(lk, ...) requires that lk actually hold the mutex.
And if lk.unlock(); is removed, this code snippet could work as expected.
#include <condition_variable>
#include <mutex>
#include <thread>
#include <functional>
#include <iostream>
#include <vector>
class Foo {
public:
Foo() {
}
void first(std::function<void()> printFirst)
{
{
std::unique_lock<std::mutex> lk(mutex);
cv1.wait(lk, [this](){return 1==state;});
doing = 1;
// printFirst() outputs "first". Do not change or remove this line.
printFirst();
state = 2;
}
cv2.notify_one();
}
void second(std::function<void()> printSecond)
{
{
std::unique_lock<std::mutex> lk(mutex);
if(state !=2 )
{
if((1 == state)&&(1 != doing))
{
//lk.unlock(); //removed
cv1.notify_one();
}
}
cv2.wait(lk, [this](){return 2==state;});
doing = 2;
// printSecond() outputs "second". Do not change or remove this line.
printSecond();
state = 3;
}
cv3.notify_one();
}
void third(std::function<void()> printThird)
{
{
std::unique_lock<std::mutex> lk(mutex);
if(state !=3 )
{
if((1 == state)&&(1 != doing))
{
//lk.unlock(); //removed
cv1.notify_one();
}
else if((2 == state)&&(2 != doing))
{
//lk.unlock(); //removed
cv2.notify_one();
}
}
cv3.wait(lk, [this](){return 3==state;});
// printThird() outputs "third". Do not change or remove this line.
printThird();
state = 3;
}
}
private:
std::condition_variable cv1;
std::condition_variable cv2;
std::condition_variable cv3;
std::mutex mutex;
int state{1};
int doing{0};
};
int main()
{
Foo foo;
std::vector<std::thread> threads;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.second([]()->void{std::cout <<"second" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.first([]()->void{std::cout <<"first" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.third([]()->void{std::cout <<"third" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::seconds(2));
for(auto itr=threads.begin(); itr!=threads.end(); itr++)
{
itr->join();
}
}
And the code snippet could be improved as this one:
#include <condition_variable>
#include <mutex>
#include <thread>
#include <functional>
#include <iostream>
#include <vector>
// #lc code=start
class Foo {
public:
Foo() {
}
void first(std::function<void()> printFirst)
{
{
std::unique_lock<std::mutex> lk(mutex);
// printFirst() outputs "first". Do not change or remove this line.
printFirst();
state = 2;
}
cv2.notify_one();
}
void second(std::function<void()> printSecond)
{
{
std::unique_lock<std::mutex> lk(mutex);
cv2.wait(lk, [this](){return 2==state;});
// printSecond() outputs "second". Do not change or remove this line.
printSecond();
state = 3;
}
cv3.notify_one();
}
void third(std::function<void()> printThird)
{
{
std::unique_lock<std::mutex> lk(mutex);
cv3.wait(lk, [this](){return 3==state;});
// printThird() outputs "third". Do not change or remove this line.
printThird();
state = 3;
}
}
private:
std::condition_variable cv2;
std::condition_variable cv3;
std::mutex mutex;
int state{1};
};
// #lc code=end
int main()
{
Foo foo;
std::vector<std::thread> threads;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.second([]()->void{std::cout <<"second" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.first([]()->void{std::cout <<"first" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.third([]()->void{std::cout <<"third" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::seconds(2));
for(auto itr=threads.begin(); itr!=threads.end(); itr++)
{
itr->join();
}
}
I'm getting started with ASIO C++ 20, which uses the coroutines. It marks awaitable, co_await and use_awaitable as "Cannot resolve symbol x". I know it's ReSharper because it works fine until ReSharper loads. The code compiled as expected, the problem is the IntelliSense bug that ReSharper causes. How can I fix it?
#include <cstdlib>
#include <deque>
#include <iostream>
#include <list>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <asio/awaitable.hpp>
#include <asio/detached.hpp>
#include <asio/co_spawn.hpp>
#include <asio/io_context.hpp>
#include <asio/ip/tcp.hpp>
#include <asio/read_until.hpp>
#include <asio/redirect_error.hpp>
#include <asio/signal_set.hpp>
#include <asio/steady_timer.hpp>
#include <asio/use_awaitable.hpp>
#include <asio/write.hpp>
using asio::ip::tcp;
using asio::awaitable;
using asio::co_spawn;
using asio::detached;
using asio::redirect_error;
using asio::use_awaitable;
//----------------------------------------------------------------------
class chat_participant
{
public:
virtual ~chat_participant() = default;
virtual void deliver(const std::string& msg) = 0;
};
typedef std::shared_ptr<chat_participant> chat_participant_ptr;
//----------------------------------------------------------------------
class chat_room
{
public:
void join(chat_participant_ptr participant)
{
participants_.insert(participant);
for (const auto &msg : recent_msgs_)
participant->deliver(msg);
}
void leave(chat_participant_ptr participant)
{
participants_.erase(participant);
}
void deliver(const std::string& msg)
{
recent_msgs_.push_back(msg);
while (recent_msgs_.size() > max_recent_msgs)
recent_msgs_.pop_front();
for (const auto &participant : participants_)
participant->deliver(msg);
}
private:
std::set<chat_participant_ptr> participants_;
enum { max_recent_msgs = 100 };
std::deque<std::string> recent_msgs_;
};
//----------------------------------------------------------------------
class chat_session
: public chat_participant,
public std::enable_shared_from_this<chat_session>
{
public:
chat_session(tcp::socket socket, chat_room& room)
: socket_(std::move(socket)),
timer_(socket_.get_executor()),
room_(room)
{
timer_.expires_at(std::chrono::steady_clock::time_point::max());
}
void start()
{
room_.join(shared_from_this());
co_spawn(socket_.get_executor(),
[self = shared_from_this()]{ return self->reader(); },
detached);
co_spawn(socket_.get_executor(),
[self = shared_from_this()]{ return self->writer(); },
detached);
}
void deliver(const std::string& msg) override
{
write_msgs_.push_back(msg);
timer_.cancel_one();
}
private:
awaitable<void> reader()
{
try
{
for (std::string read_msg;;)
{
std::size_t n = co_await asio::async_read_until(socket_,
asio::dynamic_buffer(read_msg, 1024), "\n", use_awaitable);
room_.deliver(read_msg.substr(0, n));
read_msg.erase(0, n);
}
}
catch (std::exception&)
{
stop();
}
}
awaitable<void> writer()
{
try
{
while (socket_.is_open())
{
if (write_msgs_.empty())
{
asio::error_code ec;
co_await timer_.async_wait(redirect_error(use_awaitable, ec));
}
else
{
co_await asio::async_write(socket_,
asio::buffer(write_msgs_.front()), use_awaitable);
write_msgs_.pop_front();
}
}
}
catch (std::exception&)
{
stop();
}
}
void stop()
{
room_.leave(shared_from_this());
socket_.close();
timer_.cancel();
}
tcp::socket socket_;
asio::steady_timer timer_;
chat_room& room_;
std::deque<std::string> write_msgs_;
};
//----------------------------------------------------------------------
awaitable<void> listener(tcp::acceptor acceptor)
{
chat_room room;
for (;;)
{
std::make_shared<chat_session>(
co_await acceptor.async_accept(use_awaitable),
room
)->start();
}
}
//----------------------------------------------------------------------
int main()
{
try
{
unsigned short port = 666;
asio::io_context io_context(1);
co_spawn(io_context,
listener(tcp::acceptor(io_context, { tcp::v4(), port })),
detached);
asio::signal_set signals(io_context, SIGINT, SIGTERM);
signals.async_wait([&](auto, auto) { io_context.stop(); });
io_context.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
This is an issue with R++ and the _MSC_VER predefined macro. Boost expects _MSC_VER >= 1928 in order for coroutines to be enabled, R++ defines it to 1920 at the moment in its internal preprocessor. This will be fixed in R++ 2021.2. As a workaround, you can add this snippet before the boost includes:
#ifdef __RESHARPER__
#define _MSC_VER 1928
#endif
Please report other R++ issues to ReSharper support or directly to the issue tracker. Thanks!
I am making an autoclicker with a gui in which I have a thread, but whenever I try to run it it gives me an error with abort() has been called. The breakpoint is below the line where the first thread is called. I am very new to multi-threading so I don't really know what the problem is, this is my code:
#include "AutoClicker.h"
#include <thread>
#include <iostream>
#include <conio.h>
#include <Windows.h>
#include <chrono>
using namespace std::chrono_literals;
AutoClicker::AutoClicker()
{
std::thread loop (&AutoClicker::autoClickerMain, this);
}
AutoClicker::~AutoClicker()
{
}
void AutoClicker::setCPS(int cpsIn)
{
delay = 1000 / cpsIn;
}
void AutoClicker::setHotkey(char hotkeyChar)
{
hotkey = static_cast<int>(hotkeyChar);
}
void AutoClicker::autoClickerMain()
{
int c = 0;
std::thread clicker(&AutoClicker::Clicker, this);
while (1)
{
c = 0;
c = _getch();
if (c == hotkey)
{
running = !running;
}
}
}
void AutoClicker::Clicker()
{
while (1)
{
if (running)
{
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
}
}
}
I am currently learning multithreading and semaphores and have been assigned to recreate the problem using only pthread. I found a solution that uses std::thread and have been working to convert it to pthreads, but I am having problems with the pthread_create method.
I am not sure specifically how to turn this statement
pthread_create(&threads[i], NULL, &Producer::run, &p);
into something that works with pthreads.
Here is my whole code for reference
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <deque>
#include <condition_variable>
#include <semaphore.h>
#include <queue>
#ifdef _WIN32
#include <windows.h>
void sleeps(unsigned milliseconds)
{
Sleep(milliseconds);
}
#else
#include <unistd.h>
void sleeps(unsigned milliseconds) {
usleep(milliseconds * 1000); // takes microseconds
}
#endif
class Widget {
public:
int data;
void setData(int data) {
this->data = data;
}
};
class Buffer
{
public:
void add(Widget widget) {
while (true) {
pthread_mutex_lock(&lock);
sharedBuffer.push_back(widget);
pthread_mutex_unlock(&lock);
return;
}
}
Widget remove() {
while(true) {
pthread_mutex_lock(&lock);
Widget backElem = sharedBuffer.back();
sharedBuffer.pop_back();
pthread_mutex_unlock(&lock);
return backElem;
}
}
Buffer() {}
private:
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
std::deque<Widget> sharedBuffer;
};
class Producer{
Buffer& sharedBuffer;
pthread_mutex_t coutMut;
public:
Producer(Buffer& buffer)
: sharedBuffer(buffer), coutMut(PTHREAD_MUTEX_INITIALIZER)
{}
void run() {
while(true) {
Widget widget;
widget.setData(rand() % 10);
sharedBuffer.add(widget);
pthread_mutex_lock(&coutMut);
std::cout << "Added: " << widget.data << "\n";
sleeps(50);
pthread_mutex_unlock(&coutMut);
}
}
};
class Consumer
{
Buffer& sharedBuffer;
pthread_mutex_t coutMut;
public:
Consumer(Buffer& buffer)
: sharedBuffer(buffer), coutMut(PTHREAD_MUTEX_INITIALIZER)
{}
void run() {
while(true) {
Widget widget;
widget = sharedBuffer.remove();
pthread_mutex_lock(&coutMut);
std::cout << "Removed: " << widget.data << "\n";
sleeps(50);
pthread_mutex_unlock(&coutMut);
}
}
};
int main(int argc, char *argv[]) {
typedef std::string string_std;
const int producerT = std::stoi(argv[1]);
const int consumerT = std::stoi(argv[2]);
int threadSize = producerT + consumerT;
pthread_t threads[threadSize];
void *status;
Buffer b1;
Producer p(b1);
Consumer c(b1);
for (int i = 0; i < producerT; i++) {
pthread_create(&threads[i], NULL, &Producer::run, &p);
}
for (int i = producerT; i < threadSize; i++) {
pthread_create(&threads[i], NULL, &Consumer::run, &c);
}
sleeps(5000);
for (int i = 0; i < threadSize; i++) {
pthread_join(threads[i], &status);
}
exit(0);
}
You are probably looking for something like this:
class Producer {
static void static_run(void* pThis) {
static_cast<Producer*>(pThis)->run();
}
void run() {
// Real work done here.
}
};
// At call site
Producer p;
pthread_create(&threads[i], NULL, Producer::static_run, &p);
The point is that pthread_create wants a C-style function - either a standalone non-member function, or a static member function. So you need an adapter (sometimes referred to as a "trampoline") that satisfies the requirements, and then turns around and calls the member function.
Main thread uses group of threads to search. First solution (test1) is often creating , waiting - join() and destroying threads. This works but has overhead. I try using mutex and condition_variable, but this not works,. especially for number searching threads>1.
My code:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
using namespace std;
const int NThr = 2;
struct InterchangeData {
bool endflag=false;
mutex chg_mutex;
condition_variable condition;
};
InterchangeData data;
bool execute1(InterchangeData* xchgData) {
for (int i=0; i<10; i++) {
if (xchgData->endflag) return false;
this_thread::sleep_for(chrono::milliseconds(rand()%10 +1 ));
if (rand()%100 == 50) {
lock_guard<mutex> lock(xchgData->chg_mutex);
if (!xchgData->endflag) {
printf("found!");
xchgData->endflag = true;
return true;
}
}
}
return false;
}
bool execute2(InterchangeData* xchgData) {
while (true) {
{
unique_lock<mutex> lock(xchgData->chg_mutex);
xchgData->condition.wait(lock);
}
int ret=2;
if (xchgData->endflag) ret=0;
if (execute1(xchgData)) ret=1;
{
unique_lock<mutex> lock(xchgData->chg_mutex);
xchgData->condition.notify_one();
this_thread::sleep_for(chrono::milliseconds(1));
if (ret==0) return false;
else if (ret==1) return true;
}
}
}
vector<thread*> threads;
typedef bool (*functype)(InterchangeData*);
void start(functype execute) {
for (int i=0; i<NThr; i++) {
auto t = new thread(execute, &data);
threads.push_back(t);
}
}
void stop() {
for (auto t : threads) {
t->join();
delete t;
}
threads.clear();
}
void test1() {
for (int i=0; i<10; i++) {
start(&execute1);
stop();
}
}
void test2() {
start(&execute2);
this_thread::sleep_for(chrono::milliseconds(100));
for (int i=0; i<10; i++) {
{
unique_lock<mutex> lock(data.chg_mutex);
data.condition.notify_one();
this_thread::sleep_for(chrono::milliseconds(1));
}
{
unique_lock<mutex> lock(data.chg_mutex);
data.condition.wait(lock);
}
}
{
unique_lock<mutex> lock(data.chg_mutex);
data.condition.notify_one();
this_thread::sleep_for(chrono::milliseconds(1));
}
stop();
}
int main() {
test2();
return 0;
}
Problem: is possible fast pausing/resuming execute function and main thread using condition_variable,unique_lock and wait/notify_one ?