Linux线程-互斥锁pthread_mutex_t

本文介绍如何利用互斥锁实现线程间的同步。包括互斥锁的创建、属性设置、释放及基本操作等核心内容,并通过示例代码展示了互斥锁的实际应用。

     在线程实际运行过程中,我们经常需要多个线程保持同步。这时可以用互斥锁来完成任务;互斥锁的使用过程中,主要有pthread_mutex_init,pthread_mutex_destory,pthread_mutex_lock,pthread_mutex_unlock这几个函数以完成锁的初始化,锁的销毁,上锁和释放锁操作。


一,锁的创建

    锁可以被动态或静态创建,可以用宏PTHREAD_MUTEX_INITIALIZER来静态的初始化锁,采用这种方式比较容易理解,互斥锁是pthread_mutex_t的结构体,而这个宏是一个结构常量,如下可以完成静态的初始化锁:

    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

    另外锁可以用pthread_mutex_init函数动态的创建,函数原型如下:

    int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t * attr)

二,锁的属性

    互斥锁属性可以由pthread_mutexattr_init(pthread_mutexattr_t *mattr);来初始化,然后可以调用其他的属性设置方法来设置其属性;

    互斥锁的范围:可以指定是该进程与其他进程的同步还是同一进程内不同的线程之间的同步。可以设置为PTHREAD_PROCESS_SHARE和PTHREAD_PROCESS_PRIVATE。默认是后者,表示进程内使用锁。可以使用int pthread_mutexattr_setpshared(pthread_mutexattr_t *mattr, int pshared)

pthread_mutexattr_getshared(pthread_mutexattr_t *mattr,int *pshared)

用来设置与获取锁的范围;

    互斥锁的类型:有以下几个取值空间:

  PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。

  PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。

  PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。

  PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。

可以用
pthread_mutexattr_settype(pthread_mutexattr_t *attr , int type)
pthread_mutexattr_gettype(pthread_mutexattr_t *attr , int *type)

获取或设置锁的类型。

三,锁的释放

    调用pthread_mutex_destory之后,可以释放锁占用的资源,但这有一个前提上锁当前是没有被锁的状态。

四,锁操作

    对锁的操作主要包括加锁 pthread_mutex_lock()、解锁pthread_mutex_unlock()和测试加锁 pthread_mutex_trylock()三个。

  int pthread_mutex_lock(pthread_mutex_t *mutex)

  int pthread_mutex_unlock(pthread_mutex_t *mutex)

  int pthread_mutex_trylock(pthread_mutex_t *mutex)

  pthread_mutex_trylock()语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待

五,锁的使用

  1. #include <pthread.h>  
  2. #include <stdio.h>  
  3.   
  4. pthread_mutex_t mutex ;  
  5. void *print_msg(void *arg){  
  6.         int i=0;  
  7.         pthread_mutex_lock(&mutex);  
  8.         for(i=0;i<15;i++){  
  9.                 printf("output : %d\n",i);  
  10.                 usleep(100);  
  11.         }  
  12.         pthread_mutex_unlock(&mutex);  
  13. }  
  14. int main(int argc,char** argv){  
  15.         pthread_t id1;  
  16.         pthread_t id2;  
  17.         pthread_mutex_init(&mutex,NULL);  
  18.         pthread_create(&id1,NULL,print_msg,NULL);  
  19.         pthread_create(&id2,NULL,print_msg,NULL);  
  20.         pthread_join(id1,NULL);  
  21.         pthread_join(id2,NULL);  
  22.         pthread_mutex_destroy(&mutex);  
  23.         return 1;  
  24. }  
将会一个线程一个线程的执行。
### 使用 `pthread_mutex_t` 和 `pthread_cond_t` 实现线程同步 #### 1. 线程互斥量 `pthread_mutex_t` `pthread_mutex_t` 是一种用于保护共享资源的机制,防止多个线程同时访问同一数据而导致的数据不一致问题。它通过加锁和解锁来控制对临界区的访问。 - **初始化** 可以使用静态初始化或者动态初始化两种方式创建互斥锁。 静态初始化可以直接赋值为常量 `PTHREAD_MUTEX_INITIALIZER`[^1];而动态初始化则调用函数 `pthread_mutex_init()` 来完成设置特定属性的需求。 ```c #include <pthread.h> // 动态初始化 pthread_mutex_t mutex; if (pthread_mutex_init(&mutex, NULL) != 0) { perror("Mutex initialization failed"); } ``` - **锁定与解锁** 加锁操作由 `pthread_mutex_lock()` 完成,在成功获取锁之前会阻塞当前线程直到其他持有该锁的线程释放为止。当不再需要独占访问时应立即解除锁定状态以便让其它等待中的线程继续运行下去。 ```c pthread_mutex_lock(&mutex); // Critical Section Code Here... pthread_mutex_unlock(&mutex); ``` #### 2. 条件变量 `pthread_cond_t` 条件变量允许一个或多个线程处于休眠状态直至某个指定事件发生才唤醒它们重新执行后续逻辑流程。通常配合互斥锁一起工作形成更复杂的同步模式比如生产者消费者模型等场景下非常有用。 - **初始化与销毁** 同样支持静态和动态两种方法来进行实例化处理。如果采用后者形式,则需提供额外参数指明可能存在的特殊配置选项(一般传入NULL表示接受默认行为即可)[^2]. ```c pthread_cond_t cond; // Dynamic Initialization with Attributes if (pthread_cond_init(&cond, NULL) != 0){ perror("Condition Variable Init Failed!"); } // Destruction when no longer needed. if(pthread_cond_destroy(&cond)!=0){ perror("Destroy Condition Var Error."); } ``` - **信号发送与接收** 当满足某些预定条件下可以通知单个(`pthread_cond_signal`)或多组(`pthread_cond_broadcast`)正在睡眠监听此对象变化情况下的目标进程恢复活动状态并尝试再次竞争进入受控区域的机会. ```c // Signal one waiting thread to proceed. pthread_cond_signal(&cond); // Broadcast signal so all waiters can check predicate again. pthread_cond_broadcast(&cond); ``` - **等待条件成立** 调用 `pthread_cond_wait()` 或其超时版本会使当前线程放弃持有的互斥锁并挂起自己知道被另一个地方发出相应消息之后才会自动重获先前丢失掉的那个锁然后再返回给调用方进一步判断是否真正达到了预期目的再做下一步动作[^3]. ```c while (!condition_met()) { // Predicate checking loop inside critical section. pthread_cond_wait(&cond,&mutex); } ``` #### 综合示例:生产者/消费者问题解决方案 下面给出一段简单的代码片段展示如何利用上述工具解决经典的生产和消费之间协调工作的例子: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #define BUFFER_SIZE 5 typedef struct { int buffer[BUFFER_SIZE]; int count, in, out; pthread_mutex_t lock; pthread_cond_t full, empty; } Buffer; void initBuffer(Buffer* b) { b->count = b->in = b->out = 0; pthread_mutex_init(&(b->lock), NULL); pthread_cond_init(&(b->full), NULL); pthread_cond_init(&(b->empty), NULL); } void insert_item(Buffer* b, int item) { pthread_mutex_lock(&(b->lock)); while(b->count >= BUFFER_SIZE){ printf("Producer waits.\n"); pthread_cond_wait(&(b->empty), &(b->lock)); } b->buffer[b->in] = item; b->in = (b->in + 1)%BUFFER_SIZE; ++(b->count); pthread_cond_signal(&(b->full)); pthread_mutex_unlock(&(b->lock)); } int remove_item(Buffer* b) { int item=-1; pthread_mutex_lock(&(b->lock)); while(b->count<=0){ printf("Consumer waits.\n"); pthread_cond_wait(&(b->full),&(b->lock)); } item=b->buffer[b->out]; b->out=(b->out+1)%BUFFER_SIZE; --(b->count); pthread_cond_signal(&(b->empty)); pthread_mutex_unlock(&(b->lock)); return item; } void *producer(void *arg) { Buffer *buf = arg; static int counter=0; while(1){ sleep(rand()%3+1); insert_item(buf,++counter); printf("Produced:%d\n",counter); } } void *consumer(void *arg) { Buffer *buf = arg; while(1){ sleep(rand()%4+1); int consumedItem=remove_item(buf); if(consumedItem!=-1) printf("Consumed :%d\n",consumedItem); } } int main(){ srand(time(NULL)); Buffer buf; initBuffer(&buf); pthread_t prod_thread, cons_thread; pthread_create(&prod_thread,NULL,(void*)&producer,(void*)&buf); pthread_create(&cons_thread,NULL,(void*)&consumer,(void*)&buf); pthread_join(prod_thread,NULL); pthread_join(cons_thread,NULL); return EXIT_SUCCESS; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunxiaopengsun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值