今天看到《c++编程思想》中并发一章,作者使用zThread这个开源库来讲解,于是我也下了个版本编译,并简单使用了下,以下是具体步骤:
一、创建工程
1.下载源码
由于官网http://zthread.sourceforge.net一直上不去,所以我从http://download.chinaunix.net/download.php?id=24079&ResourceID=12264下载了ZThread-2.3.1版本压缩包。解压后,只需关注include和src目录下的代码,src中还有好多平台相关的代码,放在各在平台名称命名的目录下,如linux、macos、solaris、win9x、win32。
2.创建工程
打开vs2010,创建一个windows console的空项目命名为zthread,工程目录中就产生一个D:\My Documents\Visual Studio 2010\Projects\zthread文件夹,接下去就是把需要的文件或目录拷贝到该目录下
3.将解压包中相关代码拷贝到zthread的工程目录下,注意不要破环原先的目录结构
首先只需拷贝include中文件,该目录中有库需要的头文件,include中只有一个zthread文件夹,所以将整个文件夹拷贝到工程目录 中,拷贝完成后在vs解决方案资源管理器中的头文件目录下新建一个删选器命名为zthread(删选器是一个逻辑目录,不会在磁盘中产生相应目录),这是为了使逻辑目录与磁盘中目录结构保持一致,便于代码管理,然后将刚才拷贝的目录中的所有头文件添加到该删选器下。
接下来的步骤类似,还需拷贝src目录下的所有文件(不包含文件夹)和win32文件夹到工程目录下,然后添加拷贝的文件到工程中,如果文件在win32文件夹中,需要在vs中创建响应删选器再添加文件。
4.创建一个cpp文件,写一个简单main函数。然后开始编译。
二、解决编译问题
编译过程中大概会出现几类错误:
1.打不开包含的文件
(1).如果需要的文件未添加工程,则按步骤3方式添加,之后根据编译错误还添加了posix和vanilla两个目录到工程中
(2).如果文件已经添加到了工程中,则查看include的相对路径是否正确
2.无法打开pthread.h
这个文件是posix thread中的,不在zthread包中,所以需要下载,下载路径 ftp://sourceware.org/pub/pthreads-win32/dll-latest,只需下载windows平台下的lib、dll和三个头文件,头文件分别是pthread.h, sched.h, semaphore.h,下载之后在工程目录下创建bin和lib目录,分别存放dll和lib,把3个头文件直接拷贝到工程目录下
3.程序中对pthread_t结构体使用错误
pthread_t结构体定义
typedef struct {
void * p; /* Pointer to actual object */
unsigned int x; /* Extra information - reuse count etc */
} ptw32_handle_t;
typedef ptw32_handle_t pthread_t;
程序中有几处直接对该类型对象用0初始化或者和0进行==和!=的比较,所以要稍加修改,为了不修改pthread.h 中该结构体的定义,所以自己要写个额外的类
#pragma once
#include "pthread.h"
class ThreadId
{
public:
ThreadId(const pthread_t& tid)
: tid(tid)
{
}
bool operator==(const pthread_t& tidr)const
{
return tid.p == tidr.p && tid.x == tidr.x;
}
bool operator!=(const pthread_t& tidr)const
{
return !(operator==(tidr));
}
const static pthread_t UNINIT_THREAD_ID;
private:
const pthread_t& tid;
};
const pthread_t ThreadId::UNINIT_THREAD_ID = {NULL, 0};
//使用时将ops->_tid == 0改为ThreadId(ops->_tid) == ThreadId::UNINIT_THREAD_ID
//用ThreadId::UNINIT_THREAD_ID来初始化pthread_t类型对象
4.链接错误
(1).移除 AtomicCount类的两个实现文件,一个在工程目录下,一个咋win32目录下
因为工程目录下的AtomicCount.cxx代码如下,与平台相关的条件编译在下载的源码中已经被注释,直接包含了# include "vanilla/SimpleAtomicCount.cxx",所以AtomicCount的实现文件只留vanilla目录下的SimpleAtomicCount.cxx,其他两个都移除,还有一个在win32目录下,该目录下的实现文件不全,没有实现++,--的前置和后置操作符
#ifndef __ZTATOMICCOUNTSELECT_H__
#define __ZTATOMICCOUNTSELECT_H__
#include "zthread/AtomicCount.h"
#include "zthread/Config.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
Select the correct AtomicCount implementation based on
what the compilation environment has defined
//
//#if defined(HAVE_ATOMIC_LINUX)
//# include "linux/AtomicCount.cxx"
//#elif defined(ZT_WIN32)
//# include "win32/AtomicCount.cxx"
//#elif defined(ZT_WIN9X)
//# include "win9x/AtomicCount.cxx"
//#endif
//
Default to an AtomicCount that just uses a FastLock
//#ifndef __ZTATOMICCOUNTIMPL_H__
//# include "vanilla/SimpleAtomicCount.cxx"
//#endif
# include "vanilla/SimpleAtomicCount.cxx"
#endif // __ZTATOMICCOUNTSELECT_H__
(2).错误2中下载的lib没有在工程属性中指定
需要指定lib路径,并在链接输入相中添加lib名称
三、简单测试
以上问题解决后基本可以通过编译,编译完成后还需要将错误2中保存在bin目录下的dll拷贝到exe的目录下,程序才能运行。
程序成功运行后可在main函数中加入测试代码,先写个测试类LiftOff
#pragma once
#include <iostream>
#include "zthread/Runnable.h"
class LiftOff : public ZThread::Runnable
{
public:
LiftOff(int nCountDown, int nId = 0)
: m_nCountDown(nCountDown)
, m_nId(nId)
{
}
~LiftOff()
{
std::cout<<m_nId<<" completed\n";
}
virtual void run()
{
while(m_nCountDown--)
{
std::cout<<m_nId<<":"<<m_nCountDown<<std::endl;
//Thread::yield();
}
std::cout<<"liftoff\n";
}
private:
int m_nCountDown;
int m_nId;
};
在main函数中测试
#include "LiftOff.h"
#include "zthread/Thread.h"
using namespace ZThread;
int main()
{
try
{
Thread t(new LiftOff(10));
std::cout<<"wait\n";
}
catch (Synchronization_Exception& e)
{
std::cout<<e.what()<<std::endl;
}
Thread::sleep(5000);
return 0;
}
新增:在vs2010中编译通过的zthread lib工程已上传
引申:在linux中使用zthread库发生编译错误,错误如下:
/home/scx/workspace/FsMonitor/Common/Thread/zthread/Guard.h:494:20: note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
make: *** [Common/Thread/zthread/vanilla/SimpleAtomicCount.o] Error 1
其中有个模板继承的概念,错误原因解释:http://blog.youkuaiyun.com/ddl007/article/details/6059580,可以通过设置-fpermissive选项来解决。