Linux下Epoll框架——线程同步部分

这将是我关于Linux Epoll服务器开发系列文章中的第一篇,关于线程同步的操作,大部分是原创,少部分是借鉴。

命名风格近似于Google C++ Coding Style,但根据自己的习惯做了调整。

这些代码将用于构建一个高性能的Socket服务器,贴出来的目的是与大家交流,如果有幸能为朋友们所用,请一定要记得给我反馈,方便我改进,帮助我进步,谢谢!

我的邮件地址:miscab@gmail.com

由于跨平台的代码面目可憎,暂时我只维持一个Linux的版本。

 

要编译以下代码请加入一些基本类型定义:

 

ContractedBlock.gif ExpandedBlockStart.gif Code
typedef signed char int8;
typedef 
short int16;
typedef 
int int32;
typedef 
long long int64;

typedef unsigned 
char uint8;
typedef unsigned 
short uint16;
typedef unsigned 
int uint32;
typedef unsigned 
long long uint64;

 

并加入以下的头文件定义:

 

ContractedBlock.gif ExpandedBlockStart.gif Code
#include <pthread.h>
#include 
<semaphore.h>
#include 
<sys/sem.h>
#include 
<sys/msg.h>
#include 
<sys/types.h>
#include 
<errno.h>
#include 
<sys/time.h>

 

 

1. 参考了网上的代码,融入了Google的编码风格,为每个对象定义判定初始化是否成功的bool成员变量isInitialized。

同时抽象出Lock和Unlock接口,让各类mutex和semaphore去实现具体的Lock和Unlock操作。

ContractedBlock.gif ExpandedBlockStart.gif Code
class SyncObject
{
public:
        SyncObject( ) { isInitialized 
= false; }
        
virtual ~SyncObject( ) { }
        
virtual int32 Lock  ( ) = 0;
        
virtual int32 Unlock( ) = 0;

        
bool IsInitialized() { return isInitialized; }

protected:
        
bool isInitialized;
};

class ThreadMutex : public SyncObject
{
public:
        ThreadMutex()
        {
                
if(0 != pthread_mutexattr_init(&mutexAttribute))
                {
                        isInitialized 
= false;
                        
return;
                }

                
if(0 != pthread_mutex_init(&mutexHandle, &mutexAttribute))
                {
                        pthread_mutexattr_destroy(
&mutexAttribute);
                        isInitialized 
= false;
                        
return;
                }
                isInitialized 
= true;
        }

        
virtual ~ThreadMutex()
        {
                
if(isInitialized)
                {
                        pthread_mutexattr_destroy(
&mutexAttribute);
                        pthread_mutex_destroy(
&mutexHandle);
                        isInitialized 
= false;
                }
        }

        pthread_mutex_t
* getMutex() {  return &mutexHandle; }

        
virtual int32 Lock() { return pthread_mutex_lock(&mutexHandle); }
        
virtual int32 Unlock() { return pthread_mutex_unlock(&mutexHandle); }
        
virtual int32 TryLock() { return pthread_mutex_trylock(&mutexHandle); }

protected:
        pthread_mutex_t      mutexHandle;
        pthread_mutexattr_t  mutexAttribute;
};

 

2. 读写锁的封装,Lock()等于LockRead()。

ContractedBlock.gif ExpandedBlockStart.gif Code
class ThreadReadWriteMutex : public SyncObject
{
public:
        ThreadReadWriteMutex( )
        {
                
if(0 != pthread_rwlockattr_init(&readWriteMutexHandleAttr))
                {
                        isInitialized 
= false;
                        
return;
                }

                
if(0 != pthread_rwlock_init(&readWriteMutexHandle, &readWriteMutexHandleAttr))
                {
                        pthread_rwlockattr_destroy(
&readWriteMutexHandleAttr);
                        isInitialized 
= false;
                        
return;
                }

                isInitialized 
= true;
        }

        
virtual ~ThreadReadWriteMutex()
        {
                
if(isInitialized)
                {
                        pthread_rwlockattr_destroy(
&readWriteMutexHandleAttr);
                        pthread_rwlock_destroy(
&readWriteMutexHandle);
                        isInitialized 
= false;
                }
        }

        pthread_rwlock_t
* getReadWriteMutexHandle() {  return &readWriteMutexHandle; }

        
virtual int32 LockRead() { return pthread_rwlock_rdlock(&readWriteMutexHandle); }
        
virtual int32 LockWrite() { return  pthread_rwlock_wrlock(&readWriteMutexHandle); }
        
virtual int32 Unlock() { return pthread_rwlock_unlock(&readWriteMutexHandle); }
        
virtual int32 TryLock() { return pthread_rwlock_tryrdlock(&readWriteMutexHandle); }
        
virtual int32 Lock() { return pthread_rwlock_rdlock(&readWriteMutexHandle); } //default Lock is set to LockRead

protected:
        pthread_rwlock_t      readWriteMutexHandle;
        pthread_rwlockattr_t  readWriteMutexHandleAttr;
};

 

3. 参考网上的Condition封装代码,增加了WaitTimeout接口,这样封装下来Condition的功能就与Windows平台的WaitForSingleObject非常类似了。

大家肯定都有感觉,WaitForSingleObject用起来那是相当顺手,呵呵

ContractedBlock.gif ExpandedBlockStart.gif Code
class Condition : public SyncObject
{
public:
        Condition();
        
virtual ~Condition() ;
        
void    Wait();
        
bool    WaitTimeout(int ms);

        
void    Signal() ;
        
void    SignalAll() ;

protected:
        
virtual int32 Lock();
        
virtual int32 Unlock();

private:
        
int activeWaiters;
        
bool isSendSignal;
        pthread_cond_t conditionHandle;
        ThreadMutex mutexObject;
};



Condition::Condition()
{
    isSendSignal 
= false;
    activeWaiters 
= 0;

    pthread_condattr_t condattrDetails;

    memset(
&condattrDetails, 0sizeof(condattrDetails));

    
if(0 != pthread_condattr_init(&condattrDetails))
    {
        isInitialized 
= false;
        
return;
    }
    
    
if(0 != pthread_cond_init(&conditionHandle, &condattrDetails))
    {
        isInitialized 
= false;
        
return;
    }
    
    
if(0 != pthread_condattr_destroy(&condattrDetails))
    {
        isInitialized 
= false;
        
return;
    }

    isInitialized 
= true;
}

Condition::
~Condition()
{
    uint32 retryCount 
= 0;

    
while ((EBUSY == pthread_cond_destroy(&conditionHandle)) && (retryCount <= 10))
    {
        retryCount
++;
        SignalAll();
    }

    isSendSignal 
= false;
    activeWaiters 
= 0;
    isInitialized 
= false;
}

void Condition::Wait(void)
{
    Lock();
    
    
++activeWaiters;

    
while (!isSendSignal)
    {
        pthread_cond_wait(
&conditionHandle, mutexObject.getMutex());
    }
    
    
--activeWaiters;
    
    
if (0 == activeWaiters)
    {
        isSendSignal 
= false;
    }
    
    Unlock();
}

bool Condition::WaitTimeout(int ms)
{
    
struct timespec timeout;
    
struct timeval  tp;
    
bool isTimeOut = false;
    
    gettimeofday(
&tp, NULL);
    
    timeout.tv_sec 
= (ms / 1000+ tp.tv_sec;
    timeout.tv_nsec 
= ((ms % 1000* 1000000+ (tp.tv_usec * 1000);
    
    
while (timeout.tv_nsec >= 1000000000)
    {
        timeout.tv_nsec 
-= 1000000000;
        
++timeout.tv_sec;
    }
    
    Lock();
    
    
++activeWaiters;

    int32 result 
= 0;

    
while (!isSendSignal)
    {
        
if (ETIMEDOUT == (result = pthread_cond_timedwait(&conditionHandle, mutexObject.getMutex(), &timeout)))
        {
            isTimeOut 
= true;
            
break;
        }
    }

    
--activeWaiters;

    
if ((0 == result) && 
        (
0 == activeWaiters))
    {
        isSendSignal 
= false;
    }
    
    Unlock();
    
return !isTimeOut; //if timeout return false, else true
}

void Condition::Signal(void)
{
    Lock();

    
if (!isSendSignal)
    {
        pthread_cond_signal(
&conditionHandle);
        isSendSignal 
= true;
    }

    Unlock();
}

void Condition::SignalAll(void)
{
    Lock();
    
    pthread_cond_broadcast(
&conditionHandle);
    isSendSignal 
= true;
    
    Unlock();
}

int32 Condition::Lock(
void)
{
    
return mutexObject.Lock();
}

int32 Condition::Unlock(
void)
{
    
return mutexObject.Unlock();
}

 

4. 自旋锁的封装,有的时候自旋锁比Mutex更有效率

 

ContractedBlock.gif ExpandedBlockStart.gif Code
class SpinLock : public SyncObject
{
public:
    SpinLock();
    
virtual ~SpinLock();
    
virtual int32 Lock();
    
virtual int32 Unlock();
    
virtual int32 TryLock();

private:
    pthread_spinlock_t spinLockHandle;
};


SpinLock::SpinLock()
{
    
if(0 != pthread_spin_init(&spinLockHandle, 0))
    {
        isInitialized 
= false;
    }
    
else
    {
        isInitialized 
= true;
    }
}

SpinLock::
~SpinLock()
{
    
if(isInitialized)
    {
        pthread_spin_destroy(
&spinLockHandle);
        isInitialized 
= false;
    }
}

int32 SpinLock::Lock()
{
    
return pthread_spin_lock(&spinLockHandle);
}

int32 SpinLock::Unlock()
{
    
return pthread_spin_unlock(&spinLockHandle);
}

int32 SpinLock::TryLock()
{
    
return pthread_spin_trylock(&spinLockHandle);
}

 

5. 无命名信号量的封装

 

ContractedBlock.gif ExpandedBlockStart.gif Code
class Semaphore : public SyncObject
{
public:
    Semaphore(uint32 initialCount 
= 0);
    
virtual ~Semaphore();

public:
    
virtual int32 Lock();
    
virtual int32 Unlock();
    int32 TryLock(uint32 milliseconds);
    int32 Peek();

private:
    sem_t semaphoreHandle;
};



Semaphore::Semaphore(uint32 initialCount)
{
    
if(0 != sem_init(&semaphoreHandle, 0, initialCount))
    {
        isInitialized 
= false;
    }
    
else
    {
        isInitialized 
= true;
    }
}

Semaphore::
~Semaphore()
{
    
if(isInitialized) 
    {
        
if(0 != sem_destroy(&semaphoreHandle))
        {
        
//todo
        }
        isInitialized 
= false;
    }
}

int32 Semaphore::Lock()
{
    
return sem_wait(&semaphoreHandle);
}

int32 Semaphore::TryLock(uint32 milliseconds)
{
    
const struct timespec timeOut = {0, milliseconds * 1000 * 1000 };
    
return sem_timedwait(&semaphoreHandle, &timeOut);
}

int32 Semaphore::Unlock()
{
    
return sem_post(&semaphoreHandle);
}

int32 Semaphore::Peek()
{
    int32 semaphoreValue;
    
if(0 != sem_getvalue(&semaphoreHandle, &semaphoreValue))
    {
        
return -1;
    }
    
return semaphoreValue;
}

 

6. 还有一些类似于Windows平台InterlockedIncrement之类的封装函数

 

ContractedBlock.gif ExpandedBlockStart.gif Code
/*
 * if(*lock == old)
 * {
 *     *lock = set;
 * }
 * else
 * {
 *     old = *lock;
 * }
 
*/
static inline uint32 AtomicCompareAndSet(
    uint32 
*lock
    uint32 old,
    uint32 
set)
{
    uint8 res;
    __asm__ 
volatile (
    
"lock;"
    
"cmpxchgl %3, %1;"
    
"sete    %0;"
    : 
"=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc""memory");
    
return res;
}

static inline int32 AtomicAdd(uint32 *value, int32 add)
{
    __asm__ 
volatile (
        
"lock;" 
        
"xaddl  %0, %1;"
        :
"+r" (add) : "m" (*value) : "cc""memory");
    
return add;
}

static inline int32 AtomicIncrement(uint32 *value)
{
    
return AtomicAdd(value, 1);
}

static inline int32 AtomicDecrement(uint32 *value)
{
    
return AtomicAdd(value, -1);
}

 

也差不多了,我写代码用的也就是这些,剩下的还有命名信号量用起来挺舒服的,就像Windows的NamedEvent,用于进程或线程的同步。

有时间把命名信号量封装出来。

转载于:https://www.cnblogs.com/miscab/archive/2009/05/21/1486466.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值