一个简单案例理解为什么在多线程的应用中要使用锁

简介: 一个简单案例理解为什么在多线程的应用中要使用锁

需求:使用10个线程,同时对一个值count进行加一操作,每个线程对count加100000次,最终使得count=1000000

第一版代码:不加锁

lock.c

#include<stdio.h>
#include<pthread.h>
#define THREAD_COUNT 10
void *thread_callback(void *arg){
  int *pcount=(int*)arg;
  int i=0;
  while(i++ < 100000){
    (*pcount)++;
    usleep(1);//休眠一毫秒
  }
}
int main(){
  pthread_t threadid[THREAD_COUNT]={0};//定义多线程
  int i=0;
  int count=0;
  for(i=0;i<THREAD_COUNT;i++){
    pthread_create(&threadid[i],NULL,thread_callback,&count);
  }
    //每隔一秒打印一次count值
  for(i=0;i<100;i++){
    printf("count: %d\n",count);
    sleep(1);//休眠一秒
  }
  return 0; 
}

在Linux环境下编译执行:

编译:  gcc -o lock lock.c -pthread

执行: ./lock

运行结果:

在不加锁的情况之下,使用多线程无法满足需求,即count值无法加到1000000.

从代码分析唯一能改变count值得代码是:count++,源代码中为:(*pcount)++

count++转化为汇编语言为:

 

正常情况(预期情况):每一个线程的count++都执行完再执行另外一个线程的count++

eax:寄存器

 

不正常情况(实际情况):当前线程中count++没完全执行完就跳转到另外一个线程执行

 

线程在执行代码的过程中被打断,这样所带来的的结果就是两个线程中执行两次count++,但count实际值只加了1,使得结果不能达到我们所预期的1000000值.

解决方法:使用互斥锁,或自旋锁,或原子操作。

第二版代码:这里使用互斥锁(mutex)

#include<stdio.h>
#include<pthread.h>
#define THREAD_COUNT 10
pthread_mutex_t mutex;//定义一个锁
void *thread_callback(void *arg){
  int *pcount=(int*)arg;
  int i=0;
  while(i++ < 100000){
#if 0
    (*pcount)++;
#else
    pthread_mutex_lock(&mutex);//上锁
    (*pcount)++;
    pthread_mutex_unlock(&mutex);//解锁
#endif
    usleep(1);//休眠一毫秒
  }
}
int main(){
  pthread_t threadid[THREAD_COUNT]={0};//定义多线程
  pthread_mutex_init(&mutex,NULL);//初始化锁,NULL为系统默认
  int i=0;
  int count=0;
  for(i=0;i<THREAD_COUNT;i++){
    pthread_create(&threadid[i],NULL,thread_callback,&count);
  }
  for(i=0;i<100;i++){
    printf("count: %d\n",count);
    sleep(1);//休眠一秒
  }
  return 0; 
}

运行结果:

 

 

 

 

 

 

目录
打赏
0
0
0
0
1
分享
相关文章
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
在Python开发中,GIL(全局解释器锁)一直备受关注。本文基于CPython解释器,探讨GIL的技术本质及其对程序性能的影响。GIL确保同一时刻只有一个线程执行代码,以保护内存管理的安全性,但也限制了多线程并行计算的效率。文章分析了GIL的必要性、局限性,并介绍了多进程、异步编程等替代方案。尽管Python 3.13计划移除GIL,但该特性至少要到2028年才会默认禁用,因此理解GIL仍至关重要。
133 16
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
JAVA线程池有哪些队列? 以及它们的适用场景案例
不同的线程池队列有着各自的特点和适用场景,在实际使用线程池时,需要根据具体的业务需求、系统资源状况以及对任务执行顺序、响应时间等方面的要求,合理选择相应的队列来构建线程池,以实现高效的任务处理。
129 12
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
433 6
Java线程管理:守护线程与用户线程的区分与应用
在Java多线程编程中,线程可以分为守护线程(Daemon Thread)和用户线程(User Thread)。这两种线程在行为和用途上有着明显的区别,了解它们的差异对于编写高效、稳定的并发程序至关重要。
69 2
PHP 互斥锁:如何确保代码的线程安全?
在多线程和高并发环境中,确保代码段互斥执行至关重要。本文介绍了 PHP 互斥锁库 `wise-locksmith`,它提供多种锁机制(如文件锁、分布式锁等),有效解决线程安全问题,特别适用于电商平台库存管理等场景。通过 Composer 安装后,开发者可以利用该库确保在高并发下数据的一致性和安全性。
61 6
Python中的多线程编程及其在数据处理中的应用
本文深入探讨了Python中多线程编程的概念、原理和实现方法,并详细介绍了其在数据处理领域的应用。通过对比单线程与多线程的性能差异,展示了多线程编程在提升程序运行效率方面的显著优势。文章还提供了实际案例,帮助读者更好地理解和掌握多线程编程技术。
【JavaEE“多线程进阶”】——各种“锁”大总结
乐/悲观锁,轻/重量级锁,自旋锁,挂起等待锁,普通互斥锁,读写锁,公不公平锁,可不可重入锁,synchronized加锁三阶段过程,锁消除,锁粗化
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
105 8
深入理解ThreadLocal:线程局部变量的机制与应用
在Java的多线程编程中,`ThreadLocal`变量提供了一种线程安全的解决方案,允许每个线程拥有自己的变量副本,从而避免了线程间的数据竞争。本文将深入探讨`ThreadLocal`的工作原理、使用方法以及在实际开发中的应用场景。
128 2
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####

相关实验场景

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等