跨平台(windows+linux)的线程辅助程序,跨平台(Windows+Linux)的线程辅助程序(转)

【好久没写文章了,因为在忙一个项目,这个项目需要编写跨平台(windows+Linux)代码,所以对跨平台的东西做了些关注,本文及下来几篇文章都是针对跨平台的。】

如果一个项目需要跨平台,可选择的编程语言就受到一定的限制,如果再考虑运行效率,可选择的语言似乎只能是C/C++了。与Java不同,C/C++是被操作系统“原生态”支持的,因而各操作系统实现的方式也略有不同,各自做了不同的扩展,而不象Java一样有统一库函数及接口。

用C/C++做跨平台开发需要考虑操作系统的不同,当然,有别人写好的跨平台库,这当中,最著名的就是boost了。本文不是讨论boost的文章,笔者认为,如果开发难度不大,自己开发也不错,可以充分了解各操作系统的特点,因此,本文涉及的是自己写一些简单的跨平台的东西。

因为项目的性质,需要多线程,因此首先需要解决的是多线程方面的编程,这里,涉及两方面内容:

1.线程的创建(启动)与停止。

2.全局数据读写的同步(即互斥量的应用)。

一、Windows下的线程函数和互斥量

Windows下的线程函数有多种表达(这跟windows的发展历史有关或是跟windows的开发接口习惯有关,Windows的开发接口总是形式多样,以下互斥量也是如此)。MFC中有AfxCreateThread,AfxEndThread等函数,Win32API中有CreateThread,ExitThread等,随VC一起的有_beginThread和_endThread等。直接使用Win32 API中的线程函数,但又在在线程中调用某些CRT中的函数,就会有一点小的内存泄露(http://support.microsoft.com/kb/104641/),因此建议采用_beginThread、_endThread来创建和中止线程(本文不考虑用MFC库)。

Windows下的线程或进程间同步的手段大体上有 event, mutex, semaphore, timer object这几类。

event:一个线程等待信号,另一个线程发出信号。

semaphore:一个线程或多个线程占有资源,其它线程等待,即某个资源同时只能被n个线程占有,第n+1个线程只能等待。

mutex:是semaphore的一个特殊情况,一个线程占有资源,另外的线程等待资源。

大部分情况下,mutex已能满足我们的要求,所以本文也只涉及了mutex。

二、Linux下的线程函数和互斥量

Linux下的线程函数为pthread_create和pthread_exit,比较简单,需要注意的是,线程入口函数略有不同,pthread_create要求的线程函数为 void * (* proc)( void * ),而_beginThread要求的线程函数为void  (* proc)( void * ),即返回值不同,为统一化,只能舍弃Linux下的线程函数的返回值。好在如果需要线程函数的返回值,可以定义一个全局变量来解决此问题。

Linux下的线程同步手段比较单一,有mutex和条件变量。互斥量操的函数为pthread_mutex_init,pthread_mutex_destroy等,条件变量类似于event,但需要与互斥量共同作用(如果是微软,可能会将二者合起来,这是微软一贯的风格)。同样需要注意的是,Linux中的互斥量没有名称,也就是它只能采用全局变量这种方式,并且不能运用到进程,而windows下的互斥量可以是命名互斥量,也可用于进程间同步。

Linux和Windows另一个不同是等待函数,Windows下的等待函数有两个:WaitForSingleObject和WaitForMultipleObjects,分别用于等待一个同步量和多个同步量,并有“超时”的概念,Linux下的等待函数有pthread_mutex_lock和pthread_mutex_trylock,只能等待一个同步量,没有“超时”的概念,为实现“超时”,本文采用一个简单的办法(见下面的实现)。

从Windows和Linux编程接口函数的比较,可以看出微软的接口确实比较“贴心”,但有时也会造成接口函数过多,刚开始时无所适从,例如C#的线程同步,方式多得使人眼花。

三、线程辅助程序代码

说明文件(lightthread.h)代码。

[cpp]view plaincopy

#ifndef _LIGHTTHREAD_H_

#define _LIGHTTHREAD_H_

#include "platform.h"

#if defined(_WIN32_PLATFORM_)

typedef void *   Mutex_Handle;

#endif

#if defined(_LINUX_PLATFORM_)

typedef pthread_mutex_t   Mutex_Handle;

#endif

class CLightThread

{

public:

CLightThread() {};

~CLightThread()  {};

static int CreateThread(void ( *proc )( void * ), void *pargs);

static void EndThread();

static unsigned int GetCurrentThreadId();

static void Sleep(unsigned int milliseconds);

static void DiscardTimeSlice();

};

class CLightThreadMutex

{

public:

CLightThreadMutex();

~CLightThreadMutex();

int Lock();

int TryLock(unsigned int dwMilliseconds);

void Unlock();

private:

Mutex_Handle m_hMutex;

};

typedef struct

{

unsigned int errorno;

char errormsg[512];

} thread_error_t;

class CThreadError

{

typedef struct

{

thread_error_t threaderror;

unsigned int threadid;

void * next;

} internal_thread_error_t;

public:

CThreadError();

~CThreadError();

void operator=(int errorno);

void operator=(const char * msg);

void operator=(thread_error_t & st);

unsigned int GetLastErrorNo();

const char *GetLastErrorMsg();

const thread_error_t *GetLastErrorStruct();

private:

internal_thread_error_t* m_pStart;

internal_thread_error_t* allocMemory(unsigned int tid);

internal_thread_error_t * search(unsigned int tid);

};

#endif

实现文件(lightthread.cpp)代码。

[cpp]view plaincopy

#include 

#include 

#include 

#include "lightthread.h"

#if defined(_WIN32_PLATFORM_)

#include 

#include     /* _beginthread, _endthread */

#define gxstrcpy(d,n,s) strcpy_s(d,n,s)

#endif

#if defined(_LINUX_PLATFORM_)

#include 

#include 

#include 

#include 

#define gxstrcpy(d,n,s) strncpy(d,s,n)

#define THREAD_IDLE_TIMESLICE_MS   20

#endif

#define GX_UNDEFINED      0xffffffff

#define GX_S_OK           0x00000000

#include "TimeSpan.h"

#if defined(_LINUX_PLATFORM_)

typedef struct

{

void (* proc)( void * ) ;

void * pargs;

} _threadwraper_linux_t;

void * _ThreadWraper_Linux(void *pargs)

{

_threadwraper_linux_t *pth= (_threadwraper_linux_t *)pargs;

pth->proc(pth->pargs);

delete[] pth;

return NULL;

}

int CLightThread::CreateThread(void ( *proc )( void * ), void *pargs)

{

pthread_t ntid;

_threadwraper_linux_t* pthreadwraper = new _threadwraper_linux_t[1];

pthreadwraper[0].proc = proc;

pthreadwraper[0].pargs = pargs;

return pthread_create(&ntid, NULL, _ThreadWraper_Linux, pthreadwraper);

}

void CLightThread::DiscardTimeSlice()

{

usleep(THREAD_IDLE_TIMESLICE_MS*1000);

}

void CLightThread::EndThread()

{

pthread_exit(NULL);

}

unsigned int CLightThread::GetCurrentThreadId()

{

return pthread_self();

}

void CLightThread::Sleep(unsigned int milliseconds)

{

if(milliseconds>=1000)

{

unsigned int s = milliseconds/1000;

unsigned int us = milliseconds  - s*1000;

sleep(s);

if(us>0)  usleep(us*1000);

}

else

{

usleep(milliseconds*1000);

}

}

//=====================================================================================

CLightThreadMutex::CLightThreadMutex()

{

pthread_mutex_init(&m_hMutex, NULL);

}

CLightThreadMutex::~CLightThreadMutex()

{

pthread_mutex_destroy(&m_hMutex);

}

int CLightThreadMutex::Lock()

{

return pthread_mutex_lock(&m_hMutex) == 0 ?0:-1;

}

int CLightThreadMutex::TryLock(unsigned int dwMilliseconds)

{

// The function pthread_mutex_trylock() returns zero if a lock on the mutex object referenced by mutex is acquired. Otherwise, an error number is returned to indicate the error.

unsigned int us= dwMilliseconds*1000;

int rt = pthread_mutex_trylock(&m_hMutex);

if( rt == EBUSY)

{

CMyTimeSpan start;

while(rt == EBUSY)

{

if( start.GetSpaninMilliseconds()>dwMilliseconds)

{

rt = -1;

}

else

{

usleep(20000);         //sleep  20ms

rt = pthread_mutex_trylock(&m_hMutex);

}

}

}

return rt;

}

void CLightThreadMutex::Unlock()

{

pthread_mutex_unlock(&m_hMutex);

}

#endif

#if defined(_WIN32_PLATFORM_)

int CLightThread::CreateThread(void( *proc )( void * ), void *pargs)

{

return _beginthread( proc, 0, pargs );

}

void CLightThread::EndThread()

{

_endthread();

}

unsigned int CLightThread::GetCurrentThreadId()

{

return ::GetCurrentThreadId();

}

void CLightThread::Sleep(unsigned int miniseconds)

{

::Sleep(miniseconds);

}

void CLightThread::DiscardTimeSlice()

{

::SwitchToThread();

}

//=====================================================================================

//=====================================================================================

CLightThreadMutex::CLightThreadMutex()

{

m_hMutex = CreateMutexA(NULL,FALSE,NULL);

}

CLightThreadMutex::~CLightThreadMutex()

{

if(m_hMutex)   CloseHandle(m_hMutex);

}

int CLightThreadMutex::Lock()

{

if( m_hMutex && WaitForSingleObject(m_hMutex, INFINITE)==WAIT_OBJECT_0) return 0;

return -1;

}

int CLightThreadMutex::TryLock(unsigned int dwMilliseconds)

{

if( m_hMutex&& WaitForSingleObject(m_hMutex, dwMilliseconds) ==WAIT_OBJECT_0) return 0;

return -1;

}

void CLightThreadMutex::Unlock()

{

if(m_hMutex) ReleaseMutex(m_hMutex);

}

#endif

//=====================================================================================================

CThreadError::CThreadError()

{

m_pStart = NULL;

}

CThreadError::~CThreadError()

{

internal_thread_error_t *temp;

while(m_pStart)

{

temp = m_pStart;

m_pStart = (internal_thread_error_t*)m_pStart->next;

delete temp;

}

}

void CThreadError::operator=(int errorno)

{

unsigned int tid = CLightThread::GetCurrentThreadId();

internal_thread_error_t *temp = search(tid);

if(!temp)

{

temp = allocMemory(tid);

}

temp->threaderror.errorno = errorno;

temp->threaderror.errormsg[0] = "\0";

}

void CThreadError::operator=(const char * msg)

{

unsigned int tid = CLightThread::GetCurrentThreadId();

internal_thread_error_t *temp = search(tid);

if(!temp)

{

temp = allocMemory(tid);

}

temp->threaderror.errorno = GX_UNDEFINED;

gxstrcpy(temp->threaderror.errormsg, 510, msg);

}

void CThreadError::operator=(thread_error_t & st)

{

unsigned int tid = CLightThread::GetCurrentThreadId();

internal_thread_error_t *temp = search(tid);

if(!temp)

{

temp = allocMemory(tid);

}

memcpy(&temp->threaderror, &st, sizeof(thread_error_t));

}

unsigned int CThreadError::GetLastErrorNo()

{

unsigned int tid = CLightThread::GetCurrentThreadId();

internal_thread_error_t *temp = search(tid);

return temp?temp->threaderror.errorno:GX_S_OK;

}

const char *CThreadError::GetLastErrorMsg()

{

unsigned int tid = CLightThread::GetCurrentThreadId();

internal_thread_error_t *temp = search(tid);

return temp?(const char*)temp->threaderror.errormsg:NULL;

}

const thread_error_t *CThreadError::GetLastErrorStruct()

{

unsigned int tid = CLightThread::GetCurrentThreadId();

internal_thread_error_t *temp = search(tid);

return temp?(const thread_error_t *)(&(temp->threaderror)):NULL;

}

CThreadError::internal_thread_error_t* CThreadError::allocMemory(unsigned int tid)

{

internal_thread_error_t *temp = new internal_thread_error_t;

temp->threadid = tid;

temp->next = m_pStart;

m_pStart = temp;

return temp;

}

CThreadError::internal_thread_error_t * CThreadError::search(unsigned int tid)

{

internal_thread_error_t *temp = m_pStart;

while(temp)

{

if(temp->threadid == tid) break;

temp->next = (void *)temp;

}

return temp;

}

上面代码中,在不同的平台下,需要定义一个宏,_LINUX_PLATFROM_或_WIN32_PLATFROM_,对于Linux和Windows平台。CThreadError是一个线程错误类,保存了当前线程的最后一次错误值和描述。Linux版线程实现函数的TryLock中,用到一个CMyTimeSpan类,它的作用是计时,其实现代码如下:

[cpp]view plaincopy

#include "platform.h"

#if defined(_WIN32_PLATFORM_)

#include 

#define timelong_t ULARGE_INTEGER

#endif

#if defined(_LINUX_PLATFORM_)

#include 

#include 

#define timelong_t struct timeval

#endif

class CMyTimeSpan

{

public:

CMyTimeSpan();

void Reset();

unsigned long long GetSpaninMicroseconds();

unsigned int GetSpaninMilliseconds();

unsigned int GetSpaninSeconds();

private:

timelong_t m_start;

void getCurrentTimeLong(timelong_t *tl);

};

//=====================================================================================

CMyTimeSpan::CMyTimeSpan()

{

getCurrentTimeLong(&m_start);

}

void CMyTimeSpan::Reset()

{

getCurrentTimeLong(&m_start);

}

unsigned int CMyTimeSpan::GetSpaninMilliseconds()

{

return (unsigned int)(GetSpaninMicroseconds()/1000LL);

}

unsigned int CMyTimeSpan::GetSpaninSeconds()

{

return (unsigned int)(GetSpaninMicroseconds()/1000000LL);

}

unsigned long long CMyTimeSpan::GetSpaninMicroseconds()

{

timelong_t end;

getCurrentTimeLong(&end);

#if defined(_WIN32_PLATFORM_)

return (end.QuadPart - m_start.QuadPart)/10;

#endif

#if defined(_LINUX_PLATFORM_)

return 1000000LL * ( end.tv_sec - m_start.tv_sec ) + end.tv_usec - m_start.tv_usec;

#endif

}

void CMyTimeSpan::getCurrentTimeLong(timelong_t *tl)

{

#if defined(_WIN32_PLATFORM_)

FILETIME ft;

GetSystemTimeAsFileTime(&ft);

tl->HighPart= ft.dwHighDateTime;

tl->LowPart = ft.dwLowDateTime;

#endif

#if defined(_LINUX_PLATFORM_)

gettimeofday( tl, NULL);

#endif

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值