我正试图把一本书中的一些示例代码组合在一起。。但这本书和github的副本不同。。我想我即将有一个线程池的工作示例,它接受函数并封装它们,这样你就可以等待它们的值在未来返回。。。但是在模板化时出现编译错误
我试着在helloworld.cpp
的末尾实例化我需要的确切类,就像中所说的那样
为什么模板只能在头文件中实现?
但随后得到了一堆关于试图暗示一个我已经设置为=delete
的函数的警告。。。
看看我在"为什么C++11被删除的函数参与过载解决?"?
我对C++有点陌生,仍然不确定如何最好地进行,编译错误就在最后。。我已经测试了thread_safe_queue.cpp
,它已经在其他更简单的用法中工作了,所以我不认为它有错。。。因此模板需要的帮助
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
线程安全队列.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
没有模板类函数_wrapper。。我的编译器给出
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
对于的第一个错误
/src/helloworld.cpp:70:27: error: no matching member function for call to 'try_pop'
if(work_queue.try_pop(task))
您的问题是task
是std::function<void ()>
,但try_pop
需要function_wrapper&
。std::function<void ()>
没有operator function_wrapper&
,因此不能将其传递给try_pop
。您需要做的是更改try_pop
以获取const T&
,从而可以创建临时function_wrapper
,或者创建自己的function_wrapper
来封装task
并将其传递给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));
是一个拼写错误。thread_safe_queue
中没有push_back
函数,但有push
函数。你只需要更改
work_queue.push_back(std::move(task));
至
work_queue.push(std::move(task));