1线程同步:互斥量,死锁

简介:  1线程为什么要同步 A:共享资源,多个线程都可对共享资源操作。 B:线程操作共享资源的先后顺序不确定。 C:处理器对存储器的操作一般不是原子操作。 2互斥量 mutex操作原语 pthread_mutex_t pthread_mutex_init pthread_mutex_destroy pthread_mutex_loc


1线程为什么要同步

A:共享资源,多个线程都可对共享资源操作。

B:线程操作共享资源的先后顺序不确定。

C:处理器对存储器的操作一般不是原子操作。

2互斥量

mutex操作原语

pthread_mutex_t

pthread_mutex_init

pthread_mutex_destroy

pthread_mutex_lock

pthread_mutex_trylock

pthread_mutex_unlock

3临界区(Critical Section

保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。

4临界区的选定

   临界区的选定应尽可能小,如果选定太大会影响程序的并行处理性能。

5互斥量实例

依赖的头文件

#include<pthread.h>

函数声明

int pthread_mutex_destroy(pthread_mutex_t*mutex);

名称:

pthread_mutex_destroy

功能:

释放对互斥变量分配的资源

头文件:

#include <pthread.h>

函数原形:

int  pthread_mutex_destroy(pthread_mutex_t *mutex);

参数:

 

返回值:

若成功则返回0,否则返回错误编号。

 

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

名称:

pthread_mutexattr_init

功能:

初始化互斥锁。

头文件:

#include <pthread.h>

函数原形:

int pthread_mutex_init(pthread_mutex_t * mutex,

const pthread_mutex_t *attr);

参数:

mutex 互斥量

attr    互斥锁属性

返回值:

若成功则返回0,否则返回错误编号。

int pthread_mutex_lock(pthread_mutex_t*mutex);

int pthread_mutex_trylock(pthread_mutex_t*mutex);

int pthread_mutex_unlock(pthread_mutex_t*mutex);

名称:

pthread_mutex_lock/ pthread_mutex_trylock/ pthread_mutex_unlock

功能:

对互斥量加/减锁

头文件:

#include <pthread.h>

函数原形:

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_trylock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

参数:

 

返回值:

若成功则返回0,否则返回错误编号。

函数说明:

对互斥量进行加锁,需要调用pthread_mutex_lock,如果互斥量已经上锁,调用线程阻塞直至互斥量解锁。对互斥量解锁,需要调用pthread_mutex_unlock.

      如果线程不希望被阻塞,他可以使用pthread_mutex_trylock尝试对互斥量进行加锁。如果调用pthread_mutex_trylock时互斥量处于未锁住状态,那么pthread_mutex_trylock将锁住互斥量,否则就会失败,不能锁住互斥量,而返回EBUSY

 

6互斥锁创建

有两种方法创建互斥锁,静态方式和动态方式。

APOSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来静态初始化互斥锁,方法如下:

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

B:动态方式是采用pthread_mutex_init()函数来初始化互斥锁,API定义如下:

int pthread_mutex_init(pthread_mutex_t *mutex, constpthread_mutexattr_t *mutexattr);

其中mutexattr用于指定互斥锁属性,如果为NULL则使用缺省属性。

C:pthread_mutex_destroy ()用于注销一个互斥锁,API定义如下:

   intpthread_mutex_destroy(pthread_mutex_t *mutex);

D:pthread_mutex_lock()加锁

E:pthread_mutex_unlock()解锁

F:pthread_mutex_trylock()测试加锁

G:释放内存前需要调用pthread_mutex_destory.

案例说明互斥量加锁的必要性:

#include<stdio.h>

#include<pthread.h>

#include<stdlib.h>

#include<unistd.h>

 

void *thread_function(void *arg);

/*run_now代表共享资源*/

int run_now = 1;

 

int main(void)

{

   int print_count1 = 0;/*用于循环控制*/

   pthread_t a_thread;

 

   /*创建一个进程*/

   if(pthread_create(&a_thread,NULL,thread_function,NULL)){

       perror("Thread creation failed!");

       exit(1);

   }

 

   while(print_count1++ < 5){

       /*主线程:如果run_now1就把它修改为2*/

       if(run_now == 1) {

           printf("main thread is run\n");

           run_now = 2;

       } else {

           printf("main thread is sleep\n");

           sleep(1);

       }

   }

        //等待子线程结束

   pthread_join(a_thread,NULL);

   exit(0);

}

 

void *thread_function(void *arg) {

  int print_count2 = 0;

  while(print_count2++ < 5){

      if(run_now == 2) /*子线程:如果run_now1就把它修改为1*/

      {

          printf("function thread is run\n");

          run_now = 1;

      }

      else

      {

          printf("function thread is sleep\n");

          sleep(1);

      }

  }

  pthread_exit(NULL);

}

运行结果:

现象:main线程和function线程是交替运行的。它们都可以对run_now进行操作。

加锁后的代码

#include <stdio.h>

#include <pthread.h>

#include <stdio.h>

#include <stdlib.h>

 

void *thread_function(void *arg);

int run_now=1; /*run_now代表共享资源*/

pthread_mutex_t work_mutex; /*定义互斥量*/

 

int main(void) {

   int res;

   int print_count1=0;

   pthread_t a_thread;

 

   if(pthread_mutex_init(&work_mutex,NULL)!=0) /*初始化互斥量*/

   {

       perror("Mutex init faied");

       exit(1);

   }

 

   if(pthread_create(&a_thread,NULL,thread_function,NULL)!=0) /*创建新线程*/

   {

       perror("Thread createion failed");

       exit(1);

   }

 

   if(pthread_mutex_lock(&work_mutex)!=0) /*对互斥量加锁*/

   {

       perror("Lock failed");

       exit(1);

   } else {

       printf("main lock\n");

   }

 

   while(print_count1++<5) {

       if(run_now == 1) /*主线程:如果run_now1就把它修改为2*/

       {

           printf("main thread is run\n");

           run_now=2;

       } else {

           printf("main thread is sleep\n");

           sleep(1);

       }

   }

 

   if(pthread_mutex_unlock(&work_mutex)!=0) /*对互斥量解锁*/

   {

       perror("unlock failed");

       exit(1);

   } else {

       printf("main unlock\n");

   }

 

   pthread_mutex_destroy(&work_mutex); /*收回互斥量资源*/

   pthread_join(a_thread,NULL); /*等待子线程结束*/

   exit(0);

}

 

void *thread_function(void *arg) {

   int print_count2=0;

   sleep(1);

 

   if(pthread_mutex_lock(&work_mutex)!=0) {

       perror("Lock failed");

       exit(1);

   } else {

       printf("function lock\n");

   }

   

   while(print_count2++<5) {

       if(run_now==2) /*分进程:如果run_now1就把它修改为1*/

       {

           printf("function thread is run\n");

           run_now=1;

       } else {

           printf("function thread is sleep\n");

           sleep(1);

       }

   }

 

   if(pthread_mutex_unlock(&work_mutex)!=0) /*对互斥量解锁*/

   {

       perror("unlock failed");

       exit(1);

   } else {

       printf("function unlock\n");

   }

   pthread_exit(NULL);

}

运行结果如下:

总结:从运行结果可以看到,当主进程把互斥量锁住后,子进程就不能对共享资源进行操作了,只能是同步的操作了。

#include<stdio.h>

#include<stdlib.h>

#include<pthread.h>

#define NLOOP 5000

 

int counter;

pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;

 

void *doit(void *);

 

int main(int argc,char **argv){

   pthread_t tidA,tidB;

 

   pthread_create(&tidA,NULL,doit,NULL);

   pthread_create(&tidB,NULL,doit,NULL);

 

   /*wait for both thread to terminate*/

   pthread_join(tidA,NULL);

   pthread_join(tidB,NULL);

 

   return 0;

}

 

void *doit(void *vptr){

   int i,val;

   for(i = 0;i < NLOOP;i++) {

       pthread_mutex_lock(&counter_mutex);

       val = counter;

       printf("%x:%d\n",(unsigned int) pthread_self(),val + 1);

       counter = val + 1;

 

       pthread_mutex_unlock(&counter_mutex);

   }

 

   return NULL;

}

运行结果:

  1. 死锁

    A同一个线程在拥有A锁的情况下再次请求获得A

    B线程一拥有A锁,请求获得B锁;线程二拥有B锁,请求获得A锁,出现死锁,最终导致的结果是互相等待。

目录
相关文章
|
安全 Java 程序员
【多线程-从零开始-肆】线程安全、加锁和死锁
【多线程-从零开始-肆】线程安全、加锁和死锁
237 0
|
安全 算法 Java
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(下)
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)
205 6
|
存储 安全 Java
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(中)
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)
228 5
|
存储 安全 Java
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(上)
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)
177 3
|
Arthas 监控 Java
深入解析与解决高并发下的线程池死锁问题
在高并发的互联网应用中,遇到线程池死锁问题导致响应延迟和超时。问题源于库存服务的悲观锁策略和线程池配置不当。通过以下方式解决:1) 采用乐观锁(如Spring Data JPA的@Version注解)替换悲观锁,减少线程等待;2) 动态调整线程池参数,如核心线程数、最大线程数和拒绝策略,以适应业务负载变化;3) 实施超时和重试机制,减少资源占用。这些改进提高了系统稳定性和用户体验。
648 2
|
Java
死锁是线程间争夺资源造成的无限等待现象,Java示例展示了两个线程各自持有资源并等待对方释放,导致死锁。`
【6月更文挑战第20天】死锁是线程间争夺资源造成的无限等待现象,Java示例展示了两个线程各自持有资源并等待对方释放,导致死锁。`volatile`保证变量的可见性和部分原子性,确保多线程环境中值的即时更新。与`synchronized`相比,`volatile`作用于单个变量,不保证原子操作,同步范围有限,但开销较小。`synchronized`提供更全面的内存语义,保证原子性和可见性,适用于复杂并发控制。
144 3
|
Java
在Java中,死锁是指两个或多个线程互相等待对方释放资源,从而导致所有线程都无法继续执行的情况。
【6月更文挑战第24天】在Java并发中,死锁是多线程互相等待资源导致的僵局。避免死锁的关键策略包括:防止锁嵌套,设定固定的加锁顺序,使用`tryLock`带超时,避免无限等待,减少锁的持有时间,利用高级同步工具如`java.util.concurrent`,以及实施死锁检测和恢复机制。通过这些方法,可以提升程序的并发安全性。
140 1
Java多线程-死锁的出现和解决
死锁是指多线程程序中,两个或以上的线程在运行时因争夺资源而造成的一种僵局。每个线程都在等待其中一个线程释放资源,但由于所有线程都被阻塞,故无法继续执行,导致程序停滞。例如,两个线程各持有一把钥匙(资源),却都需要对方的钥匙才能继续,结果双方都无法前进。这种情况常因不当使用`synchronized`关键字引起,该关键字用于同步线程对特定对象的访问,确保同一时刻只有一个线程可执行特定代码块。要避免死锁,需确保不同时满足互斥、不剥夺、请求保持及循环等待四个条件。
142 0
|
Java 测试技术 PHP
父子任务使用不当线程池死锁怎么解决?
在Java多线程编程中,线程池有助于提升性能与资源利用效率,但若父子任务共用同一池,则可能诱发死锁。本文通过一个具体案例剖析此问题:在一个固定大小为2的线程池中,父任务直接调用`outerTask`,而`outerTask`再次使用同一线程池异步调用`innerTask`。理论上,任务应迅速完成,但实际上却超时未完成。经由`jstack`输出的线程调用栈分析发现,线程陷入等待状态,形成“死锁”。原因是子任务需待父任务完成,而父任务则需等待子任务执行完毕以释放线程,从而相互阻塞。此问题在测试环境中不易显现,常在生产环境下高并发时爆发,重启或扩容仅能暂时缓解。
286 0
Python多线程中递归锁如何解决死锁问题的详细阐述
Python多线程中递归锁如何解决死锁问题的详细阐述

热门文章

最新文章