日期:2014-05-16  浏览次数:20733 次

Linux多线程同步的几种方式
Linux多线程同步的几种方式



  线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点。linux下提供了多种方式来处理线程同步,最常用的是互斥锁、条件变量和信号量。

  1)互斥锁(mutex)

  通过锁机制实现线程间的同步。同一时刻只允许一个线程执行一个关键部分的代码。

  int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutex_attr_t *mutexattr);

  int pthread_mutex_lock(pthread_mutex *mutex);

  int pthread_mutex_destroy(pthread_mutex *mutex);

  int pthread_mutex_unlock(pthread_mutex *

  (1)先初始化锁init()或静态赋值pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIER

  attr_t有:

  PTHREAD_MUTEX_TIMED_NP:其余线程等待队列

  PTHREAD_MUTEX_RECURSIVE_NP:嵌套锁,允许线程多次加锁,不同线程,解锁后重新竞争

  PTHREAD_MUTEX_ERRORCHECK_NP:检错,与一同,线程请求已用锁,返回EDEADLK;

  PTHREAD_MUTEX_ADAPTIVE_NP:适应锁,解锁后重新竞争

  (2)加锁,lock,trylock,lock阻塞等待锁,trylock立即返回EBUSY

  (3)解锁,unlock需满足是加锁状态,且由加锁线程解锁

  (4)清除锁,destroy(此时锁必需unlock,否则返回EBUSY,//Linux下互斥锁不占用内存资源

  示例代码

  #include <cstdio>

  #include <cstdlib>

  #include <unistd.h>

  #include <pthread.h>

  #include "iostream"

  using namespace std;

  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

  int tmp;

  void* thread(void *arg)

  {

  cout << "thread id is " << pthread_self() << endl;

  pthread_mutex_lock(&mutex);

  tmp = 12;

  cout << "Now a is " << tmp << endl;

  pthread_mutex_unlock(&mutex);

  return NULL;

  }

  int main()

  {

  pthread_t id;

  cout << "main thread id is " << pthread_self() << endl;

  tmp = 3;

  cout << "In main func tmp = " << tmp << endl;

  if (!pthread_create(&id, NULL, thread, NULL))

  {

  cout << "Create thread success!" << endl;

  }

  else

  {

  cout << "Create thread failed!" << endl;

  }

  pthread_join(id, NULL);

  pthread_mutex_destroy(&mutex);

  return 0;

  }

  编译: g++ -o thread testthread.cpp -lpthread

  说明:pthread库不是Linux系统默认的库,连接时需要使用静态库libpthread.a,所以在使用pthread_create()创建线程,以及调用pthread_atfork()函数建立fork处理程序时,需要链接该库。在编译中要加 -lpthread参数。

  2)条件变量(cond)

  利用线程间共享的全局变量进行同步的一种机制。条件变量上的基本操作有:触发条件(当条件变为 true 时);等待条件,挂起线程直到其他线程触发条件。

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

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

  int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);

  int pthread_cond_destroy(pthread_cond_t *cond);

  int pthread_cond_signal(pthread_cond_t *cond);

  int pthread_cond_broadcast(pthread_cond_t *cond); //解除所有线程的阻塞

  (1)初始化.init()或者pthread_cond_t cond=PTHREAD_COND_INITIALIER(前者为动态初始化,后者为静态初始化);属性置为NULL

  (2)等待条件成立.pthread_wait,pthread_timewait.wait()释放锁,并阻塞等待条件变量为真,timewait()设置等待时间,仍未signal,返回ETIMEOUT(加锁保证只有一个线程wait)

  (3)激活条件变量:pthread_cond_signal,pthread_cond_broadcast(激活所有等待线程)

  (4)清除条件变量:destroy;无线程等待,否则返回EBUSY

  对于

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

  int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);

  一定要在mutex的锁定区域内使用。

  如果要正确的使用pthread_mutex_lock与pthread_mutex_unlock,请参考

  pthread_cleanup_push和pthread_cleanup_pop宏,它能够在线程被cancel的时候正确的释放mutex!

  另外,posix1标准说,pthread_cond_signal与pthread_cond_broadcast无需考虑调用线程是否是mutex的拥有者,也就是说,可以在lock与unlock以外的区域调用。如果我们对调用行为不关心,那么请在lock