精华内容
下载资源
问答
  • 文章目录1. 全局解释器锁(GIL)2. 为何多线程访问内存要加锁 1. 全局解释器锁(GIL) CPython解释器在内存管理...由于存在GIL锁, 所以多线程应该是串行的, 但是为什么访问内存还需要加锁呢? CPython解释器为了模拟并发执

    1. 全局解释器锁(GIL)

    • CPython解释器在内存管理上不是线程安全的, 所以创建出了一个GIL锁机制, 阻止多线程并行
    • GIL锁只存在于CPython中, 对于JPython等就没有这个概念, 但由于JPython用的人比较少, 所以支持的模块也比较少, 最常用的还是CPython

    2. 为何多线程访问内存要加锁

    • 由于存在GIL锁, 所以多线程应该是串行的, 但是为什么访问内存还需要加锁呢?
    • CPython解释器为了模拟并发执行, 默认会在线程执行100调CPU指令后(0.005s)尝试进行线程切换(修改切换时间, sys模块下sys.setswitchinterval()函数)
    • 线程block后也会释放锁(例如线程执行I/O操作时)
    展开全文
  • 我在《Linux 多线程服务端编程:使用 muduo C++ 网络库》第 1.9 节“再论 shared_ptr 的线程安全”中写道: (shared_ptr)的引用计数本身是安全且无锁的,但对象的读写则不是,因为 shared_ptr 有两个数据成员,...
  • 今天小编就大家分享一篇对Python多线程读写文件加锁的实例详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 多线程保证线程安全就是让多个线程执行的情况和单线程一样,读的时候是不影响线程安全的,但如果对数据操作,增加或者删除,几个线程同时进行,就会发生删多或者增加多的情况,这时候为了保证线程安全,就可以加对象...

     

    多线程保证线程安全就是让多个线程执行的情况和单线程一样,读的时候是不影响线程安全的,但如果对数据操作,增加或者删除,几个线程同时进行,就会发生删多或者增加多的情况,这时候为了保证线程安全,就可以加对象锁。

     

    并发不是很高的情况下,sychronized性能更好,优先选择,反之reentrantlock在高并发的情况下,性能会提高几十倍。或者使用reentrantlock三个独有的功能就选择reentrantlock:

     

    两者都是可重入锁:都是同一个线程进入会+1,直到为0才释放锁,

    两者都是阻塞的方式加锁,也就是一个线程进入锁的同步块,其他线程都必须在锁的同步代码块外面等待执行完毕。

     

    Sychronized:Reentranlock:

    1. 优点不需要自己手动释放锁,jvm会自动释放锁,所以会更安全。Reentranlock需要自己主动用unlock释放锁(必须在finally),否则线程异常,导致系统宕机
    2. Jvm实现的,是java的关键字,ReentranlockJdk1.5之后提供的类。
    3. 锁的是一整个代码块,reenTranlock方法调用实现的,更灵活。
    4. 不可以中断,等代码块正常执行完毕释放锁,或者抛出异常。
    展开全文
  • 首先需要说明一点的是:我们一直在强调 redis 是单线程,只是在处理我们的网络请求的时候只有一个线程来处理,一个正式的Redis ...为什么redis需要加锁?   我们需要注意的是:redis是单线程这是毋庸置疑的。red

    首先需要说明一点的是:我们一直在强调 redis 是单线程,只是在处理我们的网络请求的时候只有一个线程来处理,一个正式的Redis Server运行的时候肯定是不止一个线程的。

    为什么redis是单线程的?

      官方FAQ表示,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。

    为什么redis需要加锁?

      我们需要注意的是:redis是单线程这是毋庸置疑的。redis 本身是不会产生并发安全问题的,不需要加锁。再多的 commands 都是 one by one 执行的。
      这里说的加锁是我们为了满足业务在使用的时候,可能会出现并发问题而需要加锁。比如,当一个 redis 服务器同时有多个客户端访问时,每个客户端会有一个线程。客户端访问之间存在竞争。因为存在多客户端并发,所以必须保证操作的原子性。比如银行卡扣款问题,获取余额,判断,扣款,写回就必须构成事务,否则就可能出错。
      在传统单体应用单机部署的情况下,可以使用Java并发相关的锁,如ReentrantLcok或synchronized进行互斥控制。但是,随着业务发展的需要,原单体单机部署的系统,渐渐的被部署在多机器多JVM上同时提供服务,这使得原单机部署情况下的并发控制锁策略失效了,为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题。
      分布式环境下,数据一致性问题一直是一个比较重要的话题,而又不同于单进程的情况。分布式与单机情况下最大的不同在于其不是多线程而是多进程。多线程由于可以共享堆内存,因此可以简单的采取内存作为标记存储位置。而进程之间甚至可能都不在同一台物理机上,因此需要将标记存储在一个所有进程都能看到的地方
      可以用 redis 来实现分布式锁。

    分布式锁的实现条件

    1、互斥性:要保证任意时刻,只能有一个客户端持有锁。

    2、可靠性:要保证系统的稳定性,不能产生死锁。

    3、一致性:要保证锁只能由加锁人解锁,不能产生A的加锁被B用户解锁的情况。

    展开全文
  • 谈谈多线程下为何需要锁

    万次阅读 2020-08-20 20:11:36
    首先先看看不加锁的情况下多线程共享访问临界资源会发生什么. 代码很简单,开启10个线程,各加上100000,理想结果应该是10 * 100000,好的,来试试吧 ```c #include <stdio.h> #include <pthread.h> #...

    什么是锁?为什么存在?

    多个线程运行的时候,共享了同一块资源,在访问这块资源的时候就称为临界资源。为了解决这个问题,我们可以为这块资源加上一把锁,只允许一个线程访问这块资源。

    那今天就讲讲互斥锁,自旋锁。
    首先先看看不加锁的情况下多线程共享访问临界资源会发生什么.
    代码很简单,开启10个线程,各加上100000,理想结果应该是10 * 100000,好的,来试试吧

    
    ```c
    #include <stdio.h>
    #include <pthread.h>
    
    #define THREAD_NUM 10
    int count = 0;
    void *proc(void *arg)
    {
        int i = 0;
        while( i++ < 100000) {
            count++;
            usleep(1);
        }   
    }
    
    int main() 
    {
        int i = 0;
        pthread_t id[THREAD_NUM] = {0};
    
        for (i = 0; i < THREAD_NUM; i++) {
            pthread_create(&id[i], NULL, proc, NULL);
        }   
    
        while (1) {
            printf("total %d\n", count);
            sleep(1);
        }   
        return 0;
    }
    
    

    运行结果

    [guojunfeng@guojunfeng mutex]$ ./mutex 
    total 9
    total 158333
    total 317776
    total 476812
    total 634098
    total 793269
    total 943308
    total 997398
    total 997398
    total 997398
    total 997398
    total 997398
    

    很明显结果997398跟理想状态1000000少了一些,丢失的那些值去哪了呢?为什么会导致这种现象,是谁在作怪?
    可能很多同学会说count是临界资源没有加锁造成的,那为什么没有加锁达不到理想值呢?这块临界资源到底发生了什么事?

    因为count++翻译成指令,反汇编看看,其实是有三个指令,读 加 写。

    [guojunfeng@guojunfeng mutex]$ objdump -S -d mutex > count
    //找到count++的位置
    400642:   8b 05 00 0a 20 00       mov    0x200a00(%rip),%eax        # 601048 <__TMC_END__>
    400648:   83 c0 01                add    $0x1,%eax
    40064b:   89 05 f7 09 20 00       mov    %eax,0x2009f7(%rip)        # 601048 <__TMC_END__>  
    

    大概意思是:
    读取保存count到临时变量eax
    edx再自增+1
    存储edx到count


    本来理想状态是以下这样交互达到正确的++
    绝大多数的状态是这样的,线程1完成三个指令后切换线程2执行

    线程1线程2
    mov 0x200a00(%rip),%eax
    add $0x1,%eax
    mov %eax,0x2009f7(%rip)
    mov 0x200a00(%rip),%eax
    add $0x1,%eax
    mov %eax,0x2009f7(%rip)

    但有少数情况并不是上面这样的,竞争资源比较大的时候,会变成以下状态

    线程1线程2
    mov 0x200a00(%rip),%eax
    mov 0x200a00(%rip),%eax
    add $0x1,%eax
    mov %eax,0x2009f7(%rip)
    add $0x1,%eax
    mov %eax,0x2009f7(%rip)

    如果此时的count值是10,那线程1执行了第一条指令取值10至eax,切换线程2进来执行完成三条指令,此时eax是11赋值给了count寄存器。
    再次切换回线程1,线程1的临时变量eax还是10,再进行自增后11赋值给了count寄存器。
    最终这俩个线程++后的值是11,并不是12。所以这就可以解释上面代码为什么没达到理想值了。



    那我们要怎么做才能让线程1执行++的时候是不让别的线程进来呢?答案就是执行阶段加上一把锁。

    互斥锁和自旋锁:

    #include <stdio.h>
    #include <pthread.h>
    
    #define THREAD_NUM 10
    int count = 0;
    pthread_mutex_t mutex;
    pthread_spinlock_t spinlock;
    void *proc(void *arg)
    {
        int i = 0;
        while( i++ < 100000) {
    #if 1
            pthread_mutex_lock(&mutex);
            count++;
            pthread_mutex_unlock(&mutex);
    #else
            pthread_spin_lock(&spinlock);
            count++;
            pthread_spin_unlock(&spinlock);
    #endif
            usleep(1);
        }   
    }
    
    int main() 
    {
        int i = 0;
        pthread_t id[THREAD_NUM] = {0};
        pthread_mutex_init(&mutex, NULL);
    	pthread_spin_init(&spinlock, PTHREAD_PROCESS_SHARED);
    	
        for (i = 0; i < THREAD_NUM; i++) {
            pthread_create(&id[i], NULL, proc, NULL);
        }   
    
        while (1) {
            printf("total %d\n", count);
            sleep(1);
        }   
        return 0;
    }
    


    打开互斥锁代码就其实加了4行,因为是演示,锁的销毁就没处理,int pthread_mutex_destroy(pthread_mutexattr_t *attr);
    定义了一个mutex的互斥锁,进行初始化,在进行count++的时候lock,执行完再unlock。



    看下运行结果

    [guojunfeng@guojunfeng mutex]$ ./mutex 
    total 10
    total 158645
    total 316088
    total 475166
    total 635056
    total 795857
    total 955740
    total 1000000
    total 1000000
    total 1000000
    total 1000000
    

    其实打开spinlock开关结果也是正确的。
    加锁的这期间是做了什么事情呢?

    spinlock自旋,在线程切换的时候会一直在等待释放锁。
    mutex互斥,在线程切换的时候可能会干其它的事,不会一直瞎等。


    那分别应用在什么场景下?
    mutex是对于处理时间比较长的,比较复杂的
    spinlock对于时间较短,比较简单的
    以线程切换作为一个标准,如果这个处理时间超过切换线程的代价,就采用mutex,相反采用spinlock。

    展开全文
  • 本文实例讲述了Python多线程编程之多线程加锁操作。分享给大家供大家参考,具体如下: Python语言本身是支持多线程的,不像PHP语言。 下面的例子是多个线程做同一批任务,任务总是有task_num个,每次线程做一个任务...
  • 多线程加锁原因

    2016-04-22 15:11:11
    多线程编程加锁主要为了防止多个线程在同一时间访问同一资源导致的数据错误。 这句话有些笼统,通过书上介绍的例子,我觉得应该说是为了防止多个线程在同一时间访问同一资源导致访问的不是期望的数据。 比如: ...
  • 多线程应用程序中,当多个线程共享相同的内存时,如同时访问一个变量时,需要确保每个线程看到一致的数据视图,即保证所有线程对数据的修改是一致的。 一个典型的例子是,在一个多线程程序中,两个及以上个线程对...
  • Qt两种方法实现多线程的开启,及子线程的安全结束线程,及QMutex加锁,Qt单例化实现
  • 一、什么时候应该使用多线程? 今天看到一个问题,突然有感而发,想聊下这个话题。 不知道大家有没有想过这个问题,就是什么时候我该使用多线程呢?使用多线程就一定会提升系统性能吗? 1、其实是否应该使用多线程在...
  • 多线程如何实现不加锁实现高并发

    千次阅读 2020-04-12 22:52:31
    最主要的想法是运用多线程实现高并发的处理数据,用来提升对数据的处理速度,起初运用的是线程池和普通数据库连接但是并发操作会造成死锁的问题出现,原因是两个线程同时抢到了同一个资源造成的,解决方式是给执行...
  • 在单核机器上写多线程程序,仍然需要线程锁。因为线程锁通常用来实现线程的同步和通信。 在单核机器上的多线程程序,仍然存在线程同步的问题。因为在抢占式操作系统中,通常 每个线程分配一个时间片,当某个线程...
  • 1、首先介绍什么是线程为什么提出线程,优点在哪? 有人会把线程和进程搞混,线程虽然不是进程,但可以理解为轻量级的进程,进程中可以包含线程,且这些线程可以执行不同的操作。 同一进程中的线程将共享...
  • 多线程程序何时需要加锁

    千次阅读 2016-06-12 14:01:20
    对int/int64/char型是原子操作, 可不加锁, 其实没人保证这一点的, 要不c++1x还出个原子模板类干什么 常用实例 vector的[]操作是安全的, 如一个线程里 buf[0]++, 另一个buf[1]--是安全的, 因为
  • C++ mutex,lock_guard,unique_lock使用说明文档,详细属性介绍,简单使用介绍。
  • 多线程访问变量是否要加锁

    千次阅读 2017-01-09 21:35:33
    这个变量即使线程访问冲突,也没有什么大的问题,很纠结是否加锁。 询问同事,arm访问int是原子型的,可以不加锁。 网上查询了下, 1.int变量读写是否是原子操作,是平台相关的,可以看内核相应平台的atomic.h中...
  • 由于 python 解释器(Cpython interpreter)不是线程安全(thread-safe)的,所以 Cpython interpreter 的实现中使用了GIL(global interpreter lock)来阻止多线程同时在一个 pyobject 上操作。这里所说的 “不是...
  • 加锁、解锁(同步/互斥)是多线程中非常基本的操作,但我却看到不少的代码对它们处理的很不好。简单说来有三类问题,一是加锁范围太大,虽然避免了逻辑错误,但锁了不该锁的东西,难免降低程序的效率;二是该锁的不锁...
  • 今天小编就大家分享一篇Python 多线程加锁分块读取文件的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 多线程的几种加锁方式详解

    万次阅读 2016-07-17 09:47:19
    NSLock是Cocoa提供给我们最基本的锁对象,这也是我们经常使用的,除lock和unlock外,NSLock还提供了tryLock和lockBeforeDate:两个方法,前一个方法会尝试加锁,如果锁不可用(已经被锁住),并不会阻塞线程,直接...
  • 多线程加锁

    千次阅读 2018-06-10 20:52:40
    多线程加锁的过程中,注意如下两个核心关键点: 加锁的位置,加锁的位置代表了一旦其中某一线程获取锁后,其他线程就会阻塞到此位置,当加锁的线程执行完毕释放锁后,其他线程会根据阻塞时的位置继续向向执行...
  • C\C++ 多线程加锁解锁

    千次阅读 2019-04-19 14:55:11
    1、为什么多线程? 并行处理任务,更快获得计算结果。 线程编程步骤: 1 线程id申明:pthread_t pid1; 2 线程创建函数:int ret=pthread_cread(&pid1, NULL, *Fuc, (void *)Fuc_args); 线程创建成功返回值为0...
  • 关于多线程加锁问题

    千次阅读 2018-08-31 09:24:48
    偶然间翻到了多线程加锁的帖子,记录一下 多线程间共享变量加不加锁取决于变量类型以及大小,跟CPU单次操作有关。 从:https://blog.csdn.net/youtherzhang/article/details/76093570 大神的测试结果来看(感谢...
  • C++多线程map读写加锁

    千次阅读 2019-12-24 16:22:30
    # C++多线程代码参考 定义线程函数 用map接受线程返回数据 void threadClsTask(int begin, int end, vector<Mat> imgList, BSMobileNet *bsMobileNet, map<int, int> *bsInfo){ int clsRes = ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 234,514
精华内容 93,805
关键字:

多线程为什么要加锁