一.互斥量的介绍
在linux多线程中同步访问用的最普遍的是互斥量。通俗的说:程序员给某个对象加上一把“锁”,每次只允许一个线程去访问它。如果想对代码关键部分的访问进行控制,你必须在进入这段代码之前锁定一把互斥量,在完成操作之后再打开它。
posix下互斥函数:
pthread_mutex_init 初始化一个互斥量
pthread_mutex_lock 给一个互斥量加锁
pthread_mutex_trylock 加锁,如果失败不阻塞pthread_mutex_unlock 解锁
可以通过使用pthread的互斥接口保护数据,确保同一时间只有一个线程访问数据。互斥量从本质上说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁。对互斥量进行加锁以后,任何其他试图再次对互斥量加锁的线程将会被阻塞直到当前线程释放该互斥锁。如果释放互斥锁时有多个线程阻塞,所以在该互斥锁上的阻塞线程都会变成可进行状态,第一个变成运行状态的线程可以对互斥量加锁,其他线程在次被阻塞,等待下次运行状态。
互斥量用pthread_mutex_t数据类型来表示,在使用互斥量以前,必须首先对它进行初始化,可以把它置为常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量),也可以通过调用pthread_mutex_init函数进行初始化,如果动态地分配互斥量,那么释放内存前需要调用pthread_mutex_destroy.
二、初始化/回收互斥锁
1.
名称:: | pthread_mutexattr_init |
功能: | 初始化互斥锁。 |
头文件: | #include <pthread.h> |
函数原形: | int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutex_t *attr); |
参数: | mutex 互斥量 attr 互斥锁属性 |
返回值: | 若成功则返回0,否则返回错误编号。 |
mutex是我们要锁住的互斥量,attr是互斥锁的属性,可用相应的函数修改,我们在下章介绍,要用默认的属性初始化互斥量,只需把attr设置为NULL。
2.
名称:: | pthread_mutex_destroy |
功能: | 释放对互斥变量分配的资源 |
头文件: | #include <pthread.h> |
函数原形: | int pthread_mutex_destroy(pthread_mutex_t *mutex); |
参数: |
|
返回值: | 若成功则返回0,否则返回错误编号。 |
3.
名称:: | pthread_mutex_lock/ pthread_mutex_trylock/ pthread_mutex_unlock |
功能: | 对互斥量加/减锁 |
头文件: | #include <pthread.h> |
函数原形: | int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex); |
参数: |
|
返回值: | 若成功则返回0,否则返回错误编号。 |
对互斥量进行加锁,需要调用pthread_mutex_lock,如果互斥量已经上锁,调用线程阻塞直至互斥量解锁。对互斥量解锁,需要调用pthread_mutex_unlock.
如果线程不希望被阻塞,他可以使用pthread_mutex_trylock尝试对互斥量进行加锁。如果调用pthread_mutex_trylock时互斥量处于未锁住状态,那么pthread_mutex_trylock将锁住互斥量,否则就会失败,不能锁住互斥量,而返回EBUSY。
三.c++封装的类
#ifndef THREAD_LOCK_H
#define THREAD_LOCK_H
#include <assert.h>
#include <pthread.h>
#include <unistd.h>
class CMutex
{
public:
void lock()const
{
pthread_t self = pthread_self();
if ( m_owner != self )
{
pthread_mutex_lock(&m_mutex);
m_owner = self;
}
m_count++;
}
void unlock()const
{
assert(pthread_self() == m_owner);
if ( --m_count == 0)
{
m_owner = 0;
pthread_mutex_unlock(&m_muter);
}
}
CMutex()
{
m_count = 0;
m_owner = 0;
pthread_mutex_init(&m_muter,NULL);
}
~CMutex()
{
pthread_mutex_destroy(&m_muter);
}
pthread_mutex_t * get_mutex()
{
return m_muter;
}
private:
mutable pthread_mutex_t m_muter;
mutable int m_count;
mutable pthread_t m_owner;
};
class CCondMutex
{
public:
CCondMutex()
{
pthread_cond_init(&m_cond,NULL);
}
~CCondMutex()
{
pthread_cond_destroy(&m_cond);
}
void signal()
{
pthread_cond_signal(&m_cond);
}
void wait(CMutex *pmutex) const
{
pthread_cond_wait(&m_cond,pmutex->get_mutex());
}
void wait_with_timeout(CMutex *pmutex, int mill) const
{
struct timespec tv;
tv.tv_sec = mill/1000;
tv.tv_nsec = ((mill % 1000) * 1000);
pthread_cond_timedwait(&m_cond,pmutex->get_mutex(),&tv);
}
protected:
mutable pthread_cond_t m_cond;
};
inline int GetCurrentThreadid()
{
return pthread_self();
}
inline int GetCurrentProcessid()
{
return getpid();
}
class CCritical
{
public:
CCritical(const CMutex& cs) : m_mutex(cs)
{
cs.lock();
}
~CCritical()
{
m_mutex.unlock();
}
private:
const CMutex& m_mutex;
};
#define HT_CS(mutex) CCritical __critical_section(mutex)
#endif /* THREAD_LOCK_H */