linux多线程学习(四)——互斥锁线程控制

在前面的文章中提及到,一个进程中的多个线程是共享同一段资源的,由于线程对资源的竞争引出了锁。其中mutex是一种简单的加锁方法,这个互斥锁只有两种状态,那就是上锁和解锁,可以把互斥锁看作是某种意义上的全局变量。在某一时刻,只能有一个线程取得这个互斥上的锁,拥有上锁状态的线程可以对共享资源进行操作,而其他线程在该线程未解锁之前,够会被挂起,直到上锁的线程解开锁。可以这么说,互斥锁使得共享资源按序的在各个线程上操作。

互斥锁的操作主要包括互斥锁初始化、上锁、判断上锁、解锁、摧毁互斥锁。其中互斥锁可以分为快速互斥锁、递归互斥锁这检错互斥锁。这三种锁的区别主要在于其他未占有互斥锁的线程在希望得到互斥锁时是否需要等待挂起。快速锁是指调用线程会阻塞直到线程锁得到解锁为止。递归锁能够成功地返回并且增加调用线程在互斥上的加锁次数,比如一个链表在进行插入的操作时,可以进行查找的操作。检错锁则为快速互斥锁的非阻塞版本,它会立即返回并返回一个错误的信息。

1、函数简义。

(1)pthread_mutex_init

头文件:                  <pthread.h>

函数原型:               int pthread_mutex_init (pthread_mutex_t* mutex,

                                                                         const pthread_mutexattr_t* mutexattr);

函数传入值:            mutex:互斥锁。

                              mutexattr:PTHREAD_MUTEX_INITIALIZER:创建快速互斥锁。 

                                               PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP:创建递归互斥锁。

                                               PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP:创建检错互斥锁。

函数返回值:            成功:0

                              出错:-1 

(2)上锁函数:

int pthread_mutex_lock(pthread_mutex_t* mutex);

int pthread_mutex_trylock (pthread_mutex_t* mutex);

int pthread_mutex_unlock (pthread_mutex_t* mutex);

int pthread_mutex_destroy (pthread_mutex_t* mutex);

函数传入值:            mutex:互斥锁。

函数返回值:            同上。

2、互斥锁实现。

[cpp:nogutter] view
plain
copy

  1. include <stdio.h>    
  2. #include <stdlib.h>    
  3. #include <pthread.h>    
  4. #include <errno.h>    
  5. #include <unistd.h>    
  6.     
  7. #define  return_if_fail(p)  /  
  8.     if((p) == 0){printf("[%s]:func error!/n",__func__);return;}    
  9.      
  10. typedef struct _PrivInfo    
  11. {    
  12.    pthread_mutex_t mutex;    
  13.    int lock_var;    
  14.    time_t end_time;    
  15. }PrivInfo;    
  16.     
  17. static void info_init (PrivInfo* thiz);    
  18. static void* pthread_func_1 (PrivInfo* thiz);    
  19. static void* pthread_func_2 (PrivInfo* thiz);    
  20.     
  21. int main (int argc, char** argv)    
  22. {    
  23.    pthread_t pt_1 = 0;    
  24.    pthread_t pt_2 = 0;    
  25.    int ret = 0;    
  26.    PrivInfo* thiz = NULL;    
  27.     
  28.    thiz = (PrivInfo*)malloc (sizeof (PrivInfo));    
  29.    if (thiz == NULL)    
  30.    {    
  31.       return -1;    
  32.    }    
  33.     
  34.    info_init(thiz);    
  35.     
  36.    ret = pthread_create (&pt_1, NULL, (void*)pthread_func_1, thiz);    
  37.    if (ret != 0)    
  38.    {    
  39.      perror ("pthread_1_create:");    
  40.    }    
  41.        
  42.    ret = pthread_create (&pt_2, NULL, (void*)pthread_func_2, thiz);    
  43.    {    
  44.      perror ("pthread_2_create:");    
  45.    }    
  46.     
  47.    pthread_join (pt_1, NULL);    
  48.    pthread_join (pt_2, NULL);    
  49.     
  50.    pthread_mutex_destroy (&thiz->mutex);    
  51.        
  52.    free (thiz);    
  53.    thiz = NULL;    
  54.     
  55.    return 0;    
  56. }    
  57.     
  58. static void info_init (PrivInfo* thiz)    
  59. {    
  60.    return_if_fail (thiz != NULL);    
  61.     
  62.    thiz->lock_var = 0;    
  63.    thiz->end_time = time (NULL) + 10;    
  64.     
  65.    pthread_mutex_init (&thiz->mutex, NULL);    
  66.     
  67.    return;    
  68. }    
  69.     
  70. static void* pthread_func_1 (PrivInfo* thiz)    
  71. {    
  72.    return_if_fail (thiz != NULL);    
  73.     
  74.    int i = 0;    
  75.    int ret = 0;    
  76.     
  77.    while (time (NULL) < thiz->end_time)    
  78.    {    
  79.      ret  = pthread_mutex_lock (&thiz->mutex);    
  80.      if (ret != 0)    
  81.      {    
  82.          perror ("[%s]pthread_mutex_lock");    
  83.      }    
  84.      else    
  85.      {    
  86.        printf ("pthread1:pthread1 lock the variable!/n");    
  87.      }    
  88.     
  89.      for (i = 0; i < 2; i++)    
  90.      {    
  91.         sleep (1);    
  92.         thiz->lock_var ++;    
  93.      }    
  94.     
  95.      ret = pthread_mutex_unlock (&thiz->mutex);    
  96.      if (ret != 0)    
  97.      {    
  98.         perror ("[%s]pthread_mutex_unlock");    
  99.      }    
  100.      else    
  101.      {    
  102.         printf ("pthread1: pthread1 unlock the variable./n");    
  103.      }         
  104.    }    
  105.     
  106.    return;    
  107. }    
  108.     
  109. static void* pthread_func_2 (PrivInfo* thiz)    
  110. {    
  111.    return_if_fail (thiz != NULL);    
  112.     
  113.    int ret = 0;    
  114.        
  115.    while (time (NULL) < thiz->end_time)    
  116.    {    
  117.       ret = pthread_mutex_trylock (&thiz->mutex);    
  118.       if (ret == EBUSY)    
  119.       {    
  120.          printf ("pthread2:the variable is locked by thread1./n");    
  121.       }    
  122.       else    
  123.       {    
  124.          if (ret != 0)    
  125.          {    
  126.              perror ("[%s]pthread2_mutex_trylock");     
  127.          }    
  128.          else    
  129.          {    
  130.             printf ("pthread2: pthread2 lock the variable./n");    
  131.          }             
  132.           
  133.     
  134.          ret = pthread_mutex_unlock (&thiz->mutex);    
  135.          if (ret != 0)    
  136.          {    
  137.            perror ("[%s]pthread_mutex_lock");    
  138.          }    
  139.     
  140.          sleep (3);    
  141.       }    
  142.     }    
  143. }    

在上例的中,是对变量lock_var的读写进行加锁,线程一是对其进行写,在写的时候,线程二不能对其进行读。直到线程一解锁,线程二得到互斥锁,才能进行读。同样,在线程二进行读的时候,线程一不能进行写。

今天讲述到这里,下一篇文章将讲述怎样通过信号量来达到互斥锁的效果。

 

~~END~~

分享到: 

时间: 2024-10-06 08:33:05

linux多线程学习(四)——互斥锁线程控制的相关文章

艾伟:C#多线程学习(四) 多线程的自动管理(线程池)

本系列文章导航 C#多线程学习(一) 多线程的相关概念 C#多线程学习(二) 如何操纵一个线程 C#多线程学习(三) 生产者和消费者 C#多线程学习(四) 多线程的自动管理(线程池) C#多线程学习(五) 多线程的自动管理(定时器) C#多线程学习(六) 互斥对象 在多线程的程序中,经常会出现两种情况: 一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应 这一般使用ThreadPool(线程池)来解决: 另一种情况:线程平时都处于休眠状态,只是周期性地被

C#多线程学习(六)互斥对象

如何控制好多个线程相互之间的联系,不产生冲突和重复,这需要用到互斥对象,即:System.Threading 命名空间中的 Mutex 类. 我们可以把Mutex看作一个出租车,乘客看作线程.乘客首先等车,然后上车,最后下车.当一个乘客在车上时,其他乘客就只有等他下车以后才可以上车.而线程与Mutex对象的关系也正是如此,线程使用Mutex.WaitOne()方法等待Mutex对象被释放,如果它等待的Mutex对象被释放了,它就自动拥有这个对象,直到它调用Mutex.ReleaseMutex()

linux多线程学习(七)——实现“生产者和消费者”

在上一篇文章中,利用信号量实现了线程间的互斥,这一篇将要利用信号量的互斥同步机制来实现一个经典实例,就是"生产者和消费者". 1.简单描述生产者和消费者的问题. 有一个缓冲区和两个线程:生产者和消费者.生产者把产品放入缓冲区,而消费者从缓冲区中拿走.当缓冲区满时,生产者必须等待:另外,当缓冲区空时,消费者必须等待,并且缓冲区不能同时进行生产者和消费者的操作. [cpp:nogutter] view plaincopy #include <stdio.h>     #incl

linux多线程学习(六)——信号量实现同步。

信号量的互斥同步都是通过PV原语来操作的,我们可以通过注册两个信号量,让它们在互斥的问题上互动,从而达到同步.通过下面实例就可以很容易理解:   #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <pthread.h> #include <semaphore.h> #include <errno.h> #define return_if_fail(p

linux多线程学习笔记六--一次性初始化和线程私有数据【转】

转自:http://blog.csdn.net/kkxgx/article/details/7513278 版权声明:本文为博主原创文章,未经博主允许不得转载. 一,一次性初始化 以保证线程在调用资源时,确保资源已经被初始化,并且只初始化一次. 在传统的顺序编程中,一次性初始化经常通过使用布尔变量来管理.控制变量被静态初始化为0,而任何依赖于初始化的代码都能测试该变量.如果变量值仍然为0,则它能实行初始化,然后将变量置为1.以后检查的代码将跳过初始化. 但是在多线程程序设计中,事情就变的复杂的多

C#多线程学习(四)多线程的自动管理(线程池)

在多线程的程序中,经常会出现两种情况: 一种情况: 应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应 这一般使用ThreadPool(线程池)来解决: 另一种情况:线程平时都处于休眠状态,只是周期性地被唤醒 这一般使用Timer(定时器)来解决: ThreadPool类提供一个由系统维护的线程池(可以看作一个线程的容器),该容器需要 Windows 2000 以上系统支持,因为其中某些方法调用了只有高版本的Windows才有的API函数. 将线程安放在线程池里,需

linux多线程学习(二)——线程的创建和退出

      在上一篇文章中对线程进行了简单的概述,它在系统中和编程的应用中,扮演的角色是不言而喻的.学习它.掌握它.吃透它是作为一个程序员的必须作为.在接下来的讲述中,所有线程的操作都是用户级的操作.在LINUX中,一般pthread线程库是一套通用的线程库,是由POSIX提出的,因此他的移植性是非常好的.       创建线程实际上就是确定调用该线程函数的入口点,这里通常使用的函数是pthread_create.在线程创建之后,就开始运行相关的线程函数.在该函数运行结束,线程也会随着退出.这是

linux多线程学习(三)——线程属性设置。

在上一篇文章中,介绍了线程的创建和退出,以及相关函数的使用.其中pthread_create函数的第二个参数,是关于线程属性的设置,这也是今天所有讲述的.这些属性主要包括邦定属性.分离属性.堆栈地址.堆栈大小.优先级.其中系统默认的是非邦定.非分离.缺省1M的堆栈.与父进程同样级别的优先级.在pthread_create中,把第二个参数设置为NULL的话,将采用默认的属性配置. (1)绑定属性. 在LINUX中,采用的是"一对一"的线程机制.也就是一个用户线程对应一个内核线程.邦定属性

linux多线程学习(一)

进程是系统中程序执行和资源分配的基本单位.每个进程都有自己的数据段,代码段和堆栈段,这就导致了进程在进行切换等操作起到了现场保护作用.但是为了进一步减少处理机的空转时间支持多处理器和减少上下文切换开销,进程演化中出现了另外一个概念,这就是线程,也被人称为轻量级的进程.它是一个进程内的基本调度单位.线程是在共享的内存空间中并发的多道执行路径,它们共享一个进程的资源,比如文件描述符和信号处理等.因此, 大大减少了上下文切换的开销. 线程跟进程一样,都拥有一张控制表,线程将相关的变量值放在线程控制表中