在构建时,我收到以下错误:
main.obj : error LNK2019: 函数“main”中未解析的外部符号“”public: __cdecl Worker::Worker(void)”(??0Worker@@QEAA@XZ)”。
main.obj : error LNK2019: 函数“main”中未解析的外部符号“”public: virtual __cdecl Worker::~Worker(void)” (??1Worker@@UEAA@XZ)”。
我找不到问题。(我也看过这里)
主程序
#include <iostream>
#include <thread>
#include "worker.h"
using namespace std;
void pause_thread(int n)
{
std::this_thread::sleep_for (std::chrono::seconds(n));
std::cout << "pause of " << n << " seconds ended\n";
}
int main()
{
std::cout << "Spawning and detaching 3 threads...\n";
std::thread (pause_thread,1).detach();
std::thread (pause_thread,2).detach();
std::thread (pause_thread,3).detach();
std::cout << "Done spawning threads.\n";
std::cout << "(the main thread will now pause for 5 seconds)\n";
// give the detached threads time to finish (but not guaranteed!):
pause_thread(5);
Worker w;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
工人.h
#ifndef WORKER_H
#define WORKER_H
#include "jobqueue.h"
#include "job.h"
#include <mutex>
#include <thread>
using namespace std;
class Worker
{
private:
JobQueue jobs;
mutex mu;
thread & workerThread;
bool stop;
void work();
public:
Worker();
virtual ~Worker();
void addJob(Job*);
int getJobCount();
};
#endif // WORKER_H
Run Code Online (Sandbox Code Playgroud)
worker.cpp
#include "worker.h"
Worker::Worker(): workerThread(work), stop(false)
{
}
Worker::~Worker()
{
workerThread.join();
}
void Worker::work(){
while (!stop) {
unique_lock<mutex> lock(mu, defer_lock);
lock.lock();
Job* job = jobs.getNextJob();
lock.unlock();
job->run();
delete job;
}
}
void Worker::addJob(Job* job){
jobs.append(job);
}
int Worker::getJobCount(){
unique_lock<mutex> lock(mu);
return jobs.size();
}
Run Code Online (Sandbox Code Playgroud)
项目.pro
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += main.cpp \
jobqueue.cpp \
worker.cpp
HEADERS += \
jobqueue.h \
worker.h \
job.h
Run Code Online (Sandbox Code Playgroud)
删除 Project.pro.user 解决了 (main-) 问题,现在再次显示错误
您的代码中有很多错误,因为我建议您在此之前应该学习更多的 C++ 基础知识。
当我在评论中指出错误时,让我仅使用成员函数来回答您的问题:
C++ 将函数视为一等公民,而不是 Java(Java 8 改进修复了一些问题,但它也不将函数视为一等公民)。
C++ 将函数理解为可调用实体的概念:可调用实体是可以被调用的任何东西,即被视为函数。所以一个可调用的实体可以是:
全局函数:只是很好的旧 C 函数。它可以被定义、实现和调用:
void f() {}
int main()
{
f(); //Call to f
}
Run Code Online (Sandbox Code Playgroud)成员函数:经典的OO成员函数。它在一个对象内被调用,并对其数据进行操作:
struct foo
{
void f();
};
int main()
{
foo myfoo;
myfoo.f(); //Call to foo::f
}
Run Code Online (Sandbox Code Playgroud)静态成员函数:它是一个没有链接到对象的成员函数,它在类级别运行,所以它的签名与全局函数的签名相同 (记住这一点,它很重要,我们稍后会看到)
struct foo
{
static void f();
{
int main()
{
foo::f(); //Call to foo::f
}
Run Code Online (Sandbox Code Playgroud)一个函子:函子只是一个类,它的对象被设计为在函数中工作。这实现了重载 () 运算符:
struct f
{
void operator()() const
{}
};
int main()
{
f myf;
myf(); //Call to foo
}
Run Code Online (Sandbox Code Playgroud)
标准库定义了 template std::function,它是一个类型擦除的函子,旨在保存任何类型的可调用实体:
#include <functional>
void f() {}
int main()
{
std::function<void()> f_wrapper;
f_wrapper(); //Call to f_wrapper, which is an indirect call to f
}
Run Code Online (Sandbox Code Playgroud)一个 lambda 表达式:一个 lambda 表达式只是一个就地定义的匿名函子:
int main()
{
std::function<void()> lambda = [](){ std::cout << "hello!"; };
}
Run Code Online (Sandbox Code Playgroud)
你好!
指向函数的指针: C 允许用户通过函数指针存储函数,就像它允许存储指向数据的指针一样。C++ 具有相同的功能,也为成员函数进行了扩展:
void f() {}
void g( void(*function)() )
{
function(); //Call to the function referenced by the pointer passed as parameter
}
int main()
{
g(f); //Call to g passing f as parameter. Its an indirect call to f. Note that the & is not needed
}
Run Code Online (Sandbox Code Playgroud)
正如我们上面所说,静态成员函数与全局函数具有相同的签名,因此语法与上面的示例完全相同。
但是对于成员函数就不一样了:成员函数链接到一个对象,所以它在一个对象内被调用。成员函数指针的语法如下:
struct foo
{
voif f();
};
typedef void(foo::* pointer_to_f_type)();
int main()
{
pointer_to_f_pointer ptr = &foo::f; //Note that the & is needed, just like in variable pointers
foo myfoo;
(myfoo.*ptr)(); //Call to the foo member function pointed by ptr (foo::f) using myfoo as object
}
Run Code Online (Sandbox Code Playgroud)
特定签名的成员函数指针与指向相同签名的全局/静态函数的指针无关,并且不能从/向成员指针转换为非成员指针,反之亦然。
因为函数指针和成员函数指针是完全分离的东西,我们不能直接以同构的方式对待任何一种函数。例如,我们不能创建一个同时包含函数指针和成员函数指针的数组。但是,标准库提供了函数模板std::bind,它允许我们将函数绑定到一些(或全部)调用参数。也就是说,由 返回的对象std::bind()表示对可调用实体的部分(或完整)调用。
例如:
void f( int , int , int ) {}
int main()
{
std::function<void(int,int,int)> f_wrapper = f;
f(1,2,3); //Ok
f_wrapper(1,2,3); //Ok
std::function<void()> f_call = std::bind( f , 1 , 2 , 3 ); //f_call represents a partial call (Complete in this case) fo f
f_call(); //Execute the call
std::function<void(int)> partial_f_call = std::bind( f , std::placeholders::_1 , 2 , 3 );
partial_f_call( 1 ); //Same execution as above
}
Run Code Online (Sandbox Code Playgroud)
如您所见,std::bind()允许我们将某些参数绑定到一个函数,创建一个代表对函数调用的可调用实体。因此,它可用于将对象绑定到成员函数,从而使可调用实体具有std::function与任何其他类型的可调用实体初始化的实例完全相同的形式。也就是说,我们可以用std::function同样的方式来存储成员和非成员函数,并以同样的方式使用它**:
void f();
struct foo
{
void f();
};
int main()
{
std::vector<std::function<void()>> functions;
foo myfoo;
functions.push_back( f );
functions.push_back( std::bind( &foo::f , myfoo ) );
functions.push_back( [](){} );
...
for( const auto& function : functions )
function();
}
Run Code Online (Sandbox Code Playgroud)如您所见,有多种形式的可调用实体。重要的一点是有人可以使用 C++ 模板并依靠鸭子类型来使用作为参数传递的可调用实体:
template<typename F>
void call_function( const F& function )
{
function(); //function should be any kind of thing which could be called, that is, a callable entity
}
Run Code Online (Sandbox Code Playgroud)
这正是std::thread构造函数所做的。它只需要任何类型的可调用实体,一组调用参数,启动一个新线程,然后在该新线程上调用可调用实体(通过join()或detach()。它的实现可能是这样的:
template<typename F , typename... ARGS>
thread::thread( F&& function , ARGS&&... args )
{
_thread = create_thread();
_function = std::bind( std::forward<F>( function ) , std::forward<ARGS>( args )... );
}
void thread::detach()
{
detach_thread( _thread );
_function();
}
void thread::join()
{
join_thread( _thread );
_function();
}
Run Code Online (Sandbox Code Playgroud)
当然,这不是一个有效的实现,只是一个概述:p
所以现在您可以理解为什么您的方法不起作用,以及您可以做些什么来解决这个问题。具体来说,使用std::bind(),如果你想用一个成员函数的线程上创建一个可调用实体。
| 归档时间: |
|
| 查看次数: |
9706 次 |
| 最近记录: |