Linux多线程编程——线程的同步

时间:2021-02-12 11:01:23
POSIX信号量posix信号量不同于IPC中的信号量 常用的posix信号量函数 #include <semaphore.h>int sem_init(sem_t* sem,int pshared,unsigned int value);//初始化一个信号量,pshared参数指定信号量的类型,若为0,表示信号量为当前进程的局部信号量,否则,该信号量就可以在多个进程之间共享。value参数指定信号量的初始值。 int sem_destroy(sem_t* sem);//销毁一个信号量,释放它所占有的内核资源 int sem_wait(sem_t* sem);//让信号量的值减一,如果信号量的值为0,则阻塞,直到信号量的值为非0. int sem_trywait(sem_t* sem);//sem_wait的非阻塞版本,若信号量的值为0,返回一个错误值 -1,并设置errno为EAGAIN. int sem_post(sem_t* sem);//让信号量的值加1,当信号量的值大于0时,其他正在调用sem_wait的函数将被唤醒。 上面这写函数成功返回0,失败返回-1.互斥锁

互斥量相当与锁,在使用共享资源时,对它加锁,使用完后,释放锁,在加锁期间,其他的线程不能对该共享资源进行操作.

数据类型:pthread_mutex_t

相关API

初始化和销毁互斥量

初始化一个互斥量时也可以赋值为PTHREAD_MUTEX_INITIALIZER

 

int pthread_mutex_init(pthread_mutext_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

//attr设置为NULL,代表以默认属性初始化互斥量

 

int pthread_mutex_destroy(pthread_mutex_t *mutex);

 

加锁

int pthread_mutex_lock(pthread_mutex_t *mutex);

//对互斥量加锁,若互斥量已加锁,则会阻塞,直到信号量解锁,成功返回0,

 

int pthread_mutex_trylock(pthread_mutex_t *mutex);

//如果信号量没被锁,则加锁,并返回0,若信号已被锁,则不会阻塞,返回一个非0值

 

int pthread_mutex_unlock(pthread_mutex_t *mutex);

 

int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex,const struct timespec *restrict tsptr);

//当线程试图获取一个已经加锁的互斥量时,该函数可以设置等待时间,若在该时间内,互斥量被解锁,则调用该函数的线程可以继续运行,若没有解锁,则该函数不会对互斥量加锁,而是返回一个错误代码ETIMEDOUT,成功返回0

#include <stdlib.h>
#include
<unistd.h>

struct foo
{
int f_count;
pthread_mutex_t f_lock;
int f_id;
};

struct foo* foo_alloc(int id)
{
struct foo * fp;
if((fp=malloc(sizeof(struct foo))!=NULL)
{
fp
->f_count=1;
fp
->f_id=id;
if(pthread_mutex_init(&fp->f_lock,NULL)!=0)
{
free(fp);
return (NULL);
}
}

return (fp);
}

void foo_hold(struct foo * fp)
{
pthread_mutex_lock(
&fp->f_lock);
fp
->f_count++;
pthread_mutex_unlock(
&fp->f_lock);
}

void foo_rele(struct foo *fp)
{
pthread_mutex_lock(
&fp->f_lock);
if(--fp->f_count==0)
{
pthread_mutex_unlock(
&fp->f_lock);
pthread_mutex_destroy(
&fp->f_lock);
free(fp);
}
else
{
pthread_mutex_unlock(
&fp->f_lock);
}
}

读写锁

读写锁有三种状态,加读锁,加写锁,不加锁,当位于写锁时,所有企图对读写锁加锁(无论时加读锁还是写锁)的线程都会阻塞,当位于加读锁时,所有试图对其加读锁的线程可以继续运行,但是加写锁的线程会阻塞。当读写锁位于读状态时,如果有一线程试图对其加写锁,那么读写锁通常会阻塞随后的加读锁请求,这样可以避免读模式锁长期占用,而写模式锁请求得不到满足。

数据类型  pthread_rwlock_t

#include <pthread.h>

int pthread_rwclock_init(pthread_rwlock_t *restrict rwlock,const pthread_relockattr_t *restrict attr);   //初始化一个读写锁,要先分配内存。

int pthread_rwclock_destroy(pthread_rwlock_t *rwlock)    //销毁锁   。2个函数成功返回0

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);   //加读锁

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); //加写锁

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); //解锁 若成功都返回0

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);  //成功返回0

 

条件变量

如果说互斥锁用于同步线程对共享数据的访问,那么条件变量就是用于同步共享数据的值。

#include <pthread.h>

int pthread_cond_init(pthread_cond_t* cond,pthread_condattr_t* cond_attr);

初始化一个条件量,若cond_attr为NULL,则以默认熟悉初始化,还可以pthread_cond_t cond=PTHREAD_COND_INITIALIZER;

 

int pthread_cond_destroy(pthread_cond_t* cond);

int pthread_cond_signal(pthread_cond_t* cond);

唤醒一个等待该条件变量的线程

int pthread_cond_broadcast(pthread_cond_t* cond);

唤醒所有等待该条件变量的线程

 

int pthread_cond_wait(pthread_cond_t* cond,pthread_mutex_t* mutex);

等待目标条件变量,mutex用来保证该函数操作的原子性,在使用pthread_cond_wait函数之前,需保证对mutex加锁。该函数执行时,把调用线程加入条件变量的等待队列。调用完后需要对mutex解锁。

上面的函数成功返回0,失败返回错误代码。

下面是一个线程同步机制的包装类

#include <exception>
#include
<pthread.h>
#include
<semphore.h>

class sem{
public:
sem(unsigned
int val=0){
if(sem_init(&m_sem,0,val)!=0){
throw std::exception(); //constructor don't have return val,if error,throw a exception
}
}

~sem(){
sem_destroy(
&m_sem);
}

//equal p operation
bool wait(){
return sem_wait(&m_sem)==0;
}

//equal v operation
bool post(){
return sem_post(&m_sem)==0;
}
private:
sem_t m_sem;


};

class locker{
public:
locker(){
if(pthread_mutex_init(&m_mutex,NULL)!=0){
throw std::exception();
}
}

~locker(){
pthread_mutex_destroy(
&m_mutex);
}

bool lock(){
return pthread_mutex_lock(&m_mutex)==0;
}

bool unlock(){
return pthread_mutex_unlock(&m_mutex)==0;
}
private:
pthread_mutex_t m_mutex;
};

class cond{
public:
cond(){
if(pthread_mutex_init(&m_mutex,NULL)!=0){
throw std::exception();
}

if(pthread_cond_init(&m_cond,NULL)!=0){
pthread_mutex_destroy(
&m_mutex);
throw std::exception();
}
}

~cond(){
pthread_mutex_destroy(
&m_mutex);
pthread_cond_destroy(
&m_cond);
}

bool wait(){
int ret=0;
pthread_mutex_lock(
&m_mutex);
ret
=pthread_cond_wait(&m_cond,&m_mutex);
pthread_mutex_unlock(
&m_mutex);
return ret==0;
}

bool signal(){
return pthread_cond_signal(&m_cond)==0;
}

private:
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
};