Linux下多线程同步对象Mutex

Mutex:互斥(体)
  A data structure for mutual exclusion, also known as a binary semaphore. A mutex is basically just a multitasking-aware binary flag that can be used to synchronize the activities of multiple tasks. As such, it can be used to protect critical sections of the code from interruption and shared resources from simultaneous use.
  表现互斥现象的数据结构,也被当作二元信号灯。一个互斥基本上是一个多任务敏感的二元信号,它能用作同步多任务的行为,它常用作保护从中断来的临界段代码并且在共享同步使用的资源。

一、相关函数调用

1. 初始化:
  在Linux下, 线程的互斥量数据类型是pthread_mutex_t. 在使用前, 要对它进行初始化:

对于静态分配的互斥量, 可以把它设置为PTHREAD_MUTEX_INITIALIZER,或者调用pthread_mutex_init.

对于动态分配的互斥量, 在申请内存(malloc)之后, 通过pthread_mutex_init进行初始化,并且在释放内存(free)前需要调用pthread_mutex_destroy.

  原型:

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

int pthread_mutex_destroy(pthread_mutex_t *mutex);

  返回值: 成功则返回0, 出错则返回错误编号。

  说明: 如果使用默认的属性初始化互斥量, 只需把attr设为NULL. 其他值在以后讲解。

2. 互斥操作:

  对共享资源的访问, 要对互斥量进行加锁, 如果互斥量已经上了锁, 调用线程会阻塞, 直到互斥量被解锁。在完成了对共享资源的访问后, 要对互斥量进行解锁。

  首先说一下加锁函数:

  原型:

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_trylock(pthread_mutex_t *mutex);

返回值: 成功则返回0, 出错则返回错误编号。

说明: 具体说一下trylock函数, 这个函数是非阻塞调用模式, 也就是说, 如果互斥量没被锁住, trylock函数将把互斥量加锁, 并获得对共享资源的访问权限; 如果互斥量被锁住了, trylock函数将不会阻塞等待而直接返回EBUSY,表示共享资源处于忙状态。

  再说一下解锁函数:

  原型: int pthread_mutex_unlock(pthread_mutex_t *mutex);

返回值: 成功则返回0, 出错则返回错误编号。

3. 死锁:

  死锁主要发生在有多个依赖锁存在时, 会在一个线程试图以与另一个线程相反顺序锁住互斥量时发生。如何避免死锁是使用互斥量应该格外注意的东西。

  总体来讲, 有几个不成文的基本原则:

  对共享资源操作前一定要获得锁。

  完成操作以后一定要释放锁。

  尽量短时间地占用锁。

  如果有多锁, 如获得顺序是ABC连环扣, 释放顺序也应该是ABC.

  线程错误返回时应该释放它所获得的锁。

4. 示例:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int             lock_var;
time_t          end_time;
int             sum;
void pthread1(void *arg);
void pthread2(void *arg);
void pthread3(void *arg);
int main(int argc, char *argv[])
{
  pthread_t id1,id2,id3;
  pthread_t mon_th_id;
  int ret;
  sum=10;
  end_time = time(NULL)+10;
  pthread_mutex_init(&mutex,NULL);
 
  ret=pthread_create(&id1,NULL,(void *)pthread1,NULL);
  if(ret!=0)
    perror("pthread cread1");
 
  ret=pthread_create(&id2,NULL,(void *)pthread2,NULL);
  if(ret!=0)
    perror("pthread cread2");
 
  ret=pthread_create(&id3,NULL,(void *)pthread3,NULL);
  if(ret!=0)
    perror("pthread cread3");
 
  pthread_join(id1,NULL);
  pthread_join(id2,NULL);
  pthread_join(id3,NULL);
  exit(0);
}
void pthread1(void *arg)
{
  int i;
  while(time(NULL) < end_time)
  {
    if(pthread_mutex_lock(&mutex)!=0) //lock
    {
      perror("pthread_mutex_lock");
    }
    else
      printf("pthread1:pthread1 lock the variable\n");
    for(i=0;i<2;i++)
    {
      sleep(2);
      lock_var++;
    }
    if(pthread_mutex_unlock(&mutex)!=0) //unlock
    {
      perror("pthread_mutex_unlock");
    }
    else
      printf("pthread1:pthread1 unlock the variable\n");
    sleep(1);
  }
}
void pthread2(void *arg)
{
  int nolock=0;
  int ret;
  while(time(NULL) < end_time)
  {
    ret=pthread_mutex_trylock(&mutex);//try lock
    if(ret==EBUSY)
      printf("pthread2:the variable is locked by pthread1\n");
    else
    {
      if(ret!=0)
      {
        perror("pthread_mutex_trylock");
        exit(1);
      }
      else
        printf("pthread2:pthread2 got lock.The variable is %d\n",lock_var);
 
      if(pthread_mutex_unlock(&mutex)!=0)//unlock
      {
        perror("pthread_mutex_unlock");
      }
      else
        printf("pthread2:pthread2 unlock the variable\n");
    }
    sleep(1);
  }
}

void pthread3(void *arg)
{
  int nolock=0;
  int ret;
  while(time(NULL) < end_time)
  {
    ret=pthread_mutex_trylock(&mutex);
    if(ret==EBUSY)
      printf("pthread3:the variable is locked by pthread1 or 2\n");
    else
    {
      if(ret!=0)
      {
        perror("pthread_mutex_trylock");
        exit(1);
      }
      else
        printf("pthread3:pthread3 got lock.The variable is %d\n",lock_var);
 
      if(pthread_mutex_unlock(&mutex)!=0)
      {
        perror("pthread_mutex_unlock");
      }
      else
        printf("pthread3:pthread2 unlock the variable\n");
    }
    sleep(3);
  }
}

二、各种Mutex的区别

 

锁类型

初始化方式

加解锁特征

调度特征

普通锁

PTHREAD_MUTEX_INITIALIZER

同一线程可重复加锁,解锁一次释放锁

先等待锁的进程先获得锁

嵌套锁

PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP

同一线程可重复加锁,解锁同样次数才可释放锁

先等待锁的进程先获得锁

纠错锁

PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP

同一线程不能重复加锁,加上的锁只能由本线程解锁

先等待锁的进程先获得锁

自适应锁

PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP

同一线程可重加锁,解锁一次生效

所有等待锁的线程自由竞争




你可能感兴趣的:(Linux下多线程同步对象Mutex)