首先,线程也是一种资源,受系统调度。在计算机中,运行程序都是通过地址来运行,所以,我们必须告知计算机该线程的起始地址,也就是传入函数的地址,所以函数应为全局函数或者静态函数。
在c++中,传入线程的函数可能是类中的函数,如果类中的函数不加static进行修饰,可以吗?
答案是不可以的。因为在类中,参数列表中都会有一个this指针,例如函数foo(int),在编译之后就会变成foo(int, class *this),所以直接将类中的函数传给线程是不可以的,因此一般会在函数前加static,这样子编译的时候就不会产生this指针参数。
我们看一个例子:
//线程池类,将它定义为模板类是为了代码复用。模板参数T是任务类
template<typename T>
class threadpool
{
public:
/*参数thread_number是线程池中线程的数量,max_requests是请求队列中最多允许的、等待处理请求的数量 */
threadpool(int thread_number = 8, int max_requests = 10000);
~threadpool();
//往请求队列中添加任务
bool append(T* request);
//工作线程运行函数
static void* worker(void* arg);
void run();
private:
int m_thread_number; //线程池中的线程数
int m_max_requests; //请求队列中允许的最大请求数
//pthread_t* m_threads; //描述线程池的数组,其大小为m_thread_number
std::list<T*>m_workqueue; //请求队列
std::vector<std::thread> p; //vector存储线程池
std::mutex m; //锁
std::condition_variable cond; //条件变量
bool m_stop; //是否结束线程
};
template<typename T>
threadpool<T>::threadpool(int thread_number, int max_requests)
: m_thread_number(thread_number), m_max_requests(max_requests), m_stop(false)
{
if((thread_number <= 0) || (max_requests <= 0) )
throw std::exception();
//创建线程池
p.reserve(thread_number); //先一次扩容
for(int i = 0; i < thread_number; ++i)
{
p.push_back(std::thread(run));
printf("create %d process \n", i);
p[i].detach(); //线程分离
}
}
template<typename T>
void* threadpool<T>::worker(void* arg)
{
threadpool* pool = (threadpool*)arg;
pool->run();
return pool;
}
看到上面例子,我们定义了一个worker函数来作为创建线程的函数,在函数中我们立即调用了回调函数run。
如果我们将run函数直接作为启动线程的函数传入的话就会报错。