When I use mutual parameter,'some mutex',in demo of shared data in multi-threading of C++,the two errors occur,and their codes are
C2672:
'invoke': no matching overloaded function found shared_data
C2893:
Failed to specialize function template 'unknown-type std::invoke(_Callable &&) noexcept(<expr>)'
Then I looked the error codes in Microsoft VS Doc,it reads:"To fix this issue, make the template parameter member accessible where it is evaluated.",So what does the sentence mean?Finally,I guess there must be some wrong with the function invoke .
Here's the code:
#include <list>
#include <mutex>
#include <algorithm>
#include<thread>
std::list<int> some_list;
std::mutex some_mutex;
void add_to_list(int new_value)
{
std::lock_guard<std::mutex> guard(some_mutex);
some_list.push_back(new_value);
}
bool list_contains(int value_to_find)
{
std::lock_guard<std::mutex> guard(some_mutex);
return std::find(some_list.begin(), some_list.end(), value_to_find) != some_list.end();
}
int main() {
using std::thread;
thread t1(add_to_list);
thread t2(list_contains);
t1.join();
t2.join();
return 0;
}
So confused that I want to ask for help.
My comment written out as a program :
#include <cassert>
#include <list>
#include <mutex>
#include <algorithm>
#include <future>
// avoid global variable, group related functions in a class
//std::list<int> some_list;
//std::mutex some_mutex;
class my_async_list final
{
public:
void add(const int new_value) // new_value should not change so const
{
// scoped_lock instead of lock_guard https://stackoverflow.com/questions/43019598/stdlock-guard-or-stdscoped-lock
std::scoped_lock<std::mutex> lock{ m_mtx };
m_list.push_back(new_value);
}
bool contains(int value_to_find) const // contains should not change datastructure so it is a const function
{
std::scoped_lock<std::mutex> lock{ m_mtx };
return std::find(m_list.begin(), m_list.end(), value_to_find) != m_list.end();
}
private:
mutable std::mutex m_mtx; // so it can be used in const functions
std::list<int> m_list;
};
int main()
{
my_async_list my_list;
// use lambda functions to launch async function call
auto add_future = std::async(std::launch::async, [&my_list]
{
my_list.add(1);
});
auto contains_future = std::async(std::launch::async, [&my_list]
{
return my_list.contains(1);
});
add_future.get(); // wait until add is done.
bool contains_one = contains_future.get();
assert(contains_one);
return 0;
}
Related
I am attempting to put together some example code from a book.. but the book and the github copy are different.. I think I am close to having a working example of a threadpool which accepts functions and wraps them so you wait for their value to return as a future... but getting compilation errors around templating
I've tried to instantiate the exact class I need at the end of the helloworld.cpp like told in
Why can templates only be implemented in the header file?
but then proceed to get a bunch of warnings about trying to imply a function which I had set as =delete already...
see what I mean under Why do C++11-deleted functions participate in overload resolution?
I'm a bit new to C++ still so unsure how to best proceed , compilation error is at the end.. I have already tested thread_safe_queue.cpp and it worked in other simpler usages already so I don't believe it's at fault here... more so the templating is needing help
helloworld.cpp
#include <thread>
#include <vector>
#include <atomic>
#include <iostream>
#include <future>
#include <functional>
#include <unistd.h>
// https://github.com/anthonywilliams/ccia_code_samples/blob/6e7ae1d66dbd2e8f1ad18a5cf5c6d25a37b92388/listings/listing_9.1.cpp
// https://github.com/anthonywilliams/ccia_code_samples/blob/6e7ae1d66dbd2e8f1ad18a5cf5c6d25a37b92388/listings/listing_9.2.cpp
#include "thread_safe_queue.cpp"
class function_wrapper
{
struct impl_base {
virtual void call()=0;
virtual ~impl_base() {}
};
std::unique_ptr<impl_base> impl;
template<typename F>
struct impl_type: impl_base
{
F f;
impl_type(F&& f_): f(std::move(f_)) {}
void call() { f(); }
};
public:
template<typename F>
function_wrapper(F&& f):
impl(new impl_type<F>(std::move(f)))
{}
void call() { impl->call(); }
function_wrapper(function_wrapper&& other):
impl(std::move(other.impl))
{}
function_wrapper& operator=(function_wrapper&& other)
{
impl=std::move(other.impl);
return *this;
}
function_wrapper(const function_wrapper&)=delete;
function_wrapper(function_wrapper&)=delete;
function_wrapper& operator=(const function_wrapper&)=delete;
};
struct join_threads
{
join_threads(std::vector<std::thread>&)
{}
};
class thread_pool
{
std::atomic_bool done;
thread_safe_queue<function_wrapper> work_queue;
std::vector<std::thread> threads;
join_threads joiner;
void worker_thread()
{
while(!done)
{
std::function<void()> task;
if(work_queue.try_pop(task))
{
task();
}
else
{
std::this_thread::yield();
}
}
}
public:
thread_pool():
done(false),joiner(threads)
{
unsigned const thread_count=std::thread::hardware_concurrency();
try
{
for(unsigned i=0;i<thread_count;++i)
{
threads.push_back(
std::thread(&thread_pool::worker_thread,this));
}
}
catch(...)
{
done=true;
throw;
}
}
~thread_pool()
{
done=true;
}
template<typename FunctionType>
std::future<typename std::result_of<FunctionType()>::type>
submit(FunctionType f)
{
typedef typename std::result_of<FunctionType()>::type result_type;
std::packaged_task<result_type()> task(std::move(f));
std::future<result_type> res(task.get_future());
work_queue.push_back(std::move(task));
return res;
}
};
void find_the_answer_to_ltuae(){
std::cout << "About to sleep 1 second...";
sleep(1);
std::cout<<"The answer is " << 42 << std::endl;
}
int main()
{
std::cout << "About to create my_threadpool...." << std::endl;
thread_pool my_threadpool;
std::cout << "Done creating my_threadpool...." << std::endl;
std::cout << "Submitting first job now" << std::endl;
my_threadpool.submit(find_the_answer_to_ltuae);
sleep(10);
std::cout <<"Finished" << std::endl;
}
template class thread_safe_queue<function_wrapper>; // <-------- this was added by me, in an attempt to get the templating happy.. didn't work
thread_safe_queue.cpp
#include <mutex>
#include <memory>
#include <condition_variable>
#include <queue>
template <typename T>
class thread_safe_queue {
public:
// constructor
thread_safe_queue() {}
thread_safe_queue(const thread_safe_queue& other)
{
std::lock_guard<std::mutex> lock{other.mutex};
queue = other.queue;
}
void push(T new_value)
{
std::lock_guard<std::mutex> lock{mutex};
queue.push(new_value);
cond.notify_one();
}
void wait_and_pop(T& value)
{
std::unique_lock<std::mutex> lock{mutex};
cond.wait(lock, [this]{ return !queue.empty(); });
value = queue.front();
queue.pop();
}
std::shared_ptr<T> wait_and_pop()
{
std::unique_lock<std::mutex> lock{mutex};
cond.wait(lock, [this]{ return !queue.empty(); });
std::shared_ptr<T> res{std::make_shared<T>(queue.front())};
queue.pop();
return res;
}
bool try_pop(T& value)
{
std::lock_guard<std::mutex> lock{mutex};
if (queue.empty())
return false;
value = queue.front();
queue.pop();
return true;
}
std::shared_ptr<T> try_pop()
{
std::lock_guard<std::mutex> lock{mutex};
if (queue.empty())
return std::shared_ptr<T>{};
std::shared_ptr<std::mutex> res{std::make_shared<T>(queue.front())};
queue.pop();
return res;
}
bool empty() const
{
std::lock_guard<std::mutex> lock{mutex};
return queue.empty();
}
private:
mutable std::mutex mutex;
std::condition_variable cond;
std::queue<T> queue;
};
//https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file
Without the template class function_wrapper .. my compiler gives
sh compile.sh
-- Conan: Adjusting output directories
-- Conan: Using cmake targets configuration
-- Conan: Adjusting default RPATHs Conan policies
-- Conan: Adjusting language standard
-- Current conanbuildinfo.cmake directory: /build
-- Configuring done
-- Generating done
-- Build files have been written to: /build
Scanning dependencies of target test_cpp_multi
[ 33%] Building CXX object CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o
/src/helloworld.cpp:70:27: error: no matching member function for call to 'try_pop'
if(work_queue.try_pop(task))
~~~~~~~~~~~^~~~~~~
/src/thread_safe_queue.cpp:41:14: note: candidate function not viable: no known conversion from 'std::function<void ()>' to 'function_wrapper &' for 1st argument
bool try_pop(T& value)
^
/src/thread_safe_queue.cpp:51:28: note: candidate function not viable: requires 0 arguments, but 1 was provided
std::shared_ptr<T> try_pop()
^
/src/helloworld.cpp:113:20: error: no member named 'push_back' in 'thread_safe_queue<function_wrapper>'
work_queue.push_back(std::move(task));
~~~~~~~~~~ ^
2 errors generated.
make[2]: *** [CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o] Error 1
make[1]: *** [CMakeFiles/test_cpp_multi.dir/all] Error 2
make: *** [all] Error 2
For the fist error of
/src/helloworld.cpp:70:27: error: no matching member function for call to 'try_pop'
if(work_queue.try_pop(task))
Your issue is that task is a std::function<void ()>, but try_pop expects a function_wrapper&. std::function<void ()> doesn't have an operator function_wrapper&, so you can't pass it to try_pop. What you would need to do is either change try_pop to take a const T&, so a temporary function_wrapper could be created, or create you own function_wrapper that wraps task and pass that to try_pop.
Your second error of
/src/helloworld.cpp:113:20: error: no member named 'push_back' in 'thread_safe_queue<function_wrapper>'
work_queue.push_back(std::move(task));
is a typo. You don't have a push_back function in thread_safe_queue, but you do have a push function. You jus need to change
work_queue.push_back(std::move(task));
to
work_queue.push(std::move(task));
Could you please review and suggest what is wrong with this code?
It either crashes on line 21 (cond_var_.wait(lock); in the gc_thread_proc()) or locks on line 56 (lock.lock(); in release()).
#include <condition_variable>
#include <deque>
#include <functional>
#include <mutex>
#include <thread>
#include <vector>
#include <iostream>
class stream {
std::deque<int> pending_cleanups_;
std::mutex mut_{};
bool continue_{true};
std::thread gc_worker_;
std::condition_variable cond_var_;
void gc_thread_proc() {
while (true) {
std::vector<int> events_to_clean;
std::unique_lock<std::mutex> lock(mut_);
while (pending_cleanups_.empty() && continue_) {
cond_var_.wait(lock);
}
if (!continue_) {
break;
}
std::move(std::begin(pending_cleanups_), std::end(pending_cleanups_), std::back_inserter(events_to_clean));
pending_cleanups_.clear();
}
}
public:
explicit stream() : gc_worker_(&stream::gc_thread_proc, this) {}
void register_pending_event(int val) {
{
std::lock_guard<std::mutex> lock_guard(mut_);
pending_cleanups_.push_back(val);
}
cond_var_.notify_one();
}
void release() {
std::unique_lock<std::mutex> lock(mut_);
if (!continue_) {
return;
}
continue_ = false;
lock.unlock();
cond_var_.notify_one();
gc_worker_.join();
lock.lock();
pending_cleanups_.clear();
}
~stream() { release(); }
};
int main() {
int N=100000;
while(N--) {
std::cout << ".";
stream s;
}
std::cout << "ok";
return 0;
}
Changing order of members makes this problem go away - when cond_var_ is put before the gc_worker_ problem doesn't reproduce. But I guess it doesn't fix it just hides it somehow...
non-static data members are initialized in order of declaration in the class definition: https://en.cppreference.com/w/cpp/language/initializer_list
3) Then, non-static data members are initialized in order of declaration in the class definition.
In your case, since your std::thread member is initialized to start executing in its constructor, cv may not be initialized when it's used in gc_thread_proc. A command way to have a std::thread member is to move assign it in the class contructor, i.e.
class stream {
std::thread gc_worker_;
std::condition_variable cond_var_;
public:
stream(): {
gc_work = std::move(std::thread(&stream::gc_thread_proc, this));
}
};
I am implementing a threadpool that has a push_back method on callable object. However I am getting error on moving a packaged task into a function object using lambda trick.
class Threadpool {
public:
// ...
::std::deque <::std::function<void()>> _work_queue;
::std::mutex _work_queue_mutex;
::std::condition_variable _worker_signal;
template <typename CallableT>
::std::future<::std::result_of_t<CallableT()>> push_back(CallableT&&);
}
template<typename CallableT>
::std::future<::std::result_of_t<CallableT()>> Threadpool::push_back(CallableT&& callable) {
::std::packaged_task<::std::result_of_t<CallableT()>()> task (::std::move(callable));
auto fu = task.get_future();
{
::std::unique_lock<::std::mutex> locker(_work_queue_mutex);
// COMPILE ERROR
_work_queue.emplace_back([task=::std::move(task)] () { task(); })
}
_worker_signal.notify_one();
return fu;
}
Threadpool pool;
pool.emplace_back( []() { ::std::cout << "hello\n"; } );
The compiler complains about the emplace_back by error: no match for call to '(const std::packaged_task<void()>) ()' _work_queue.emplace_back([task=::std::move(task)]() { task(); }); I don't understand what's going wrong since as far as I know packaged_task is only movable and I am capturing the task by move.
There are two issues with your example.
Indeed, std::packaged_task is only movable, so [task=std::move(task)] is correct. But on top of that std::packaged_task::operator() requires not-const object: https://en.cppreference.com/w/cpp/thread/packaged_task/operator()
So the lambda must be defined as mutable to allow the usage of task():
[task=std::move(task)] () mutable { task(); };
But even so the lambda object is only movable and not copyable, while std::function requires a copyable object: https://en.cppreference.com/w/cpp/utility/functional/function
So one of the solutions, is to wrap the packaged_task in a copyable smart pointer as follows:
#include <mutex>
#include <deque>
#include <functional>
#include <condition_variable>
#include <future>
#include <iostream>
#include <type_traits>
class Threadpool
{
public:
// ...
std::deque <std::function<void()>> _work_queue;
std::mutex _work_queue_mutex;
std::condition_variable _worker_signal;
template <typename CallableT>
std::future<std::result_of_t<CallableT()>> push_back(CallableT&&);
};
template<typename CallableT>
std::future<std::result_of_t<CallableT()>> Threadpool::push_back(CallableT&& callable)
{
auto task = std::make_shared<std::packaged_task<std::result_of_t<CallableT()>()>>( std::move(callable) );
auto fu = task->get_future();
{
std::unique_lock<std::mutex> locker(_work_queue_mutex);
_work_queue.emplace_back([task]() { (*task)(); });
}
_worker_signal.notify_one();
return fu;
};
int main()
{
Threadpool pool;
pool.push_back( []() { std::cout << "hello\n"; } );
}
Demo: https://gcc.godbolt.org/z/aEfvo7Mhz
I am trying to do a threaded application to infinitely print a set of numbers after enqueing them. I get this error:
Error 1 error C3867: 'Test::ThreadFunc': function call missing argument list; use '&Test::ThreadFunc' to create a pointer to member.
What am I doing wrong? What is the mistake ?
#include "stdafx.h"
#include <chrono>
#include <mutex>
#include <thread>
#include <list>
class Test {
std::list<int> queue;
std::mutex m;
public:
void ThreadFunc()
{
// Loop is required, otherwise thread will exit
for (;;)
{
bool read = false;
int value;
{
std::lock_guard<std::mutex> lock(m);
if (queue.size())
{
value = queue.front();
read = true;
queue.pop_back();
}
}
if (read)
{
// send(header.data(), header.dataSize());
// send(proto.data(), proto.dataSize());
printf("Hello %d\n", value);
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void TestFunc()
{
std::thread thread(ThreadFunc);
thread.detach();
int i = 0;
// Loops only as a test example
for (;;)
{
std::lock_guard<std::mutex> lock(m);
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
queue.push_back(i++);
// Queue Message(header, payload);
}
}
};
int main()
{
Test test;
test.TestFunc();
}
You're attempting to pass a pointer to a member function of a class. When you do this, there's an argument added to the function, tacitly, that is a pointer to the instance of the class that you're invoking the function on. In your case, the pointer to the class will be the this pointer.
See this for syntax reference: Start thread with member function
To answer your comment, why isn't it passed implicitly? You're not calling the function as a member of a class, you're passing the member function by pointer. This is a different, unique, situation, see this reference: Passing a member function as an argument in C++
Also, to save a little future headache, the next problem that comes up is that std::thread's constructor takes its arguments by value, so if you need to pass any arguments by reference, take a look at std::ref.
Here's the fix. This works. Thank you #mock_blatt
#include "stdafx.h"
#include <chrono>
#include <mutex>
#include <thread>
#include <list>
class Test {
std::list<int> queue;
std::mutex m;
public:
void ThreadFunc()
{
// Loop is required, otherwise thread will exit
for (;;)
{
bool read = false;
int value;
{
std::lock_guard<std::mutex> lock(m);
if (queue.size())
{
value = queue.front();
read = true;
queue.pop_back();
}
}
if (read)
{
// send(header.data(), header.dataSize());
// send(proto.data(), proto.dataSize());
printf("Hello %d\n", value);
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void TestFunc()
{
std::thread thread(std::bind(&Test::ThreadFunc, this));
thread.detach();
int i = 0;
// Loops only as a test example
for (;;)
{
std::lock_guard<std::mutex> lock(m);
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
queue.push_back(i++);
// Queue Message(header, payload);
}
}
};
int main()
{
Test test;
test.TestFunc();
}
Change std::thread thread(ThreadFunc); to std::thread thread(Test::ThreadFunc, this);
I am trying to compile this on msvc 12.0, the code in the book uses the keyword thread_local but it seems msvc 12.0 does not support this? Instead of using thread_local I tried __declspec(thread) but I get the following compiler error:
Error 1 error C2483: 'this_thread_interrupt_flag' : object with constructor or destructor cannot be declared 'thread'
Here is my code:
#include <thread>
#include <atomic>
#include <future>
class interrupt_flag
{
public:
void set()
{
flag.store(true, std::memory_order_relaxed);
}
bool is_set() const
{
return flag.load(std::memory_order_relaxed);
}
private:
std::atomic<bool> flag;
};
__declspec(thread) interrupt_flag this_thread_interrupt_flag;
class interruptible_thread
{
public:
template<typename FunctionType>
interruptible_thread(FunctionType f)
{
std::promise<interrupt_flag*> p;
internal_thread = std::thread([f, &p] {
p.set_value(&this_thread_interrupt_flag);
f();
});
flag = p.get_future().get();
}
void interrupt()
{
if (flag)
{
flag->set();
}
}
private:
std::thread internal_thread;
interrupt_flag* flag;
};
Is there any workarounds for this in msvc 12.0?