首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

linux 读写锁 互斥锁

Linux 读写锁与互斥锁基础概念

互斥锁(Mutex)

互斥锁是一种同步机制,用于保护共享资源不被多个线程同时访问。当一个线程获得互斥锁时,其他试图获得该锁的线程将被阻塞,直到锁被释放。

优势:

  • 确保同一时间只有一个线程访问共享资源,防止数据竞争和不一致性。

类型:

  • 二进制互斥锁(Binary Mutex):只能锁定一次。
  • 计数互斥锁(Counting Mutex):可以锁定多次。

应用场景:

  • 当需要对临界区进行严格保护时,如修改全局变量或访问共享内存。

示例代码:

代码语言:txt
复制
#include <pthread.h>
#include <stdio.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int shared_data = 0;

void* thread_func(void* arg) {
    pthread_mutex_lock(&mutex);
    shared_data++;
    pthread_mutex_unlock(&mutex);
    return NULL;
}

int main() {
    pthread_t thread1, thread2;
    pthread_create(&thread1, NULL, thread_func, NULL);
    pthread_create(&thread2, NULL, thread_func, NULL);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    printf("Shared data: %d\n", shared_data);
    return 0;
}

读写锁(Reader-Writer Lock)

读写锁允许多个线程同时读取共享资源,但只允许一个线程写入。这种锁适用于读操作远多于写操作的场景。

优势:

  • 提高并发性能,允许多个读操作并行执行,减少线程阻塞。

类型:

  • 公平读写锁:按照请求顺序分配锁。
  • 非公平读写锁:不保证请求顺序,可能导致写线程饥饿。

应用场景:

  • 当读操作远远多于写操作时,如缓存系统、配置文件读取等。

示例代码:

代码语言:txt
复制
#include <pthread.h>
#include <stdio.h>

pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
int shared_data = 0;

void* reader(void* arg) {
    pthread_rwlock_rdlock(&rwlock);
    printf("Read: %d\n", shared_data);
    pthread_rwlock_unlock(&rwlock);
    return NULL;
}

void* writer(void* arg) {
    pthread_rwlock_wrlock(&rwlock);
    shared_data++;
    printf("Write: %d\n", shared_data);
    pthread_rwlock_unlock(&rwlock);
    return NULL;
}

int main() {
    pthread_t reader_thread1, reader_thread2, writer_thread;
    pthread_create(&reader_thread1, NULL, reader, NULL);
    pthread_create(&reader_thread2, NULL, reader, NULL);
    pthread_create(&writer_thread, NULL, writer, NULL);
    pthread_join(reader_thread1, NULL);
    pthread_join(reader_thread2, NULL);
    pthread_join(writer_thread, NULL);
    return 0;
}

遇到的问题及解决方法

问题:死锁(Deadlock)

当两个或多个线程互相等待对方释放资源时,就会发生死锁。

原因:

  • 循环等待:线程A等待线程B释放资源,而线程B又在等待线程A释放资源。
  • 持有并等待:线程持有至少一个资源,并等待获取其他线程持有的资源。
  • 非抢占式分配:资源只能由持有它的线程主动释放。

解决方法:

  1. 避免循环等待: 使用资源分配图或层次锁策略。
  2. 持有并等待: 线程在开始执行前请求所有需要的资源。
  3. 使用超时机制: 在获取锁时设置超时,避免无限期等待。

示例代码(使用超时机制):

代码语言:txt
复制
#include <pthread.h>
#include <stdio.h>
#include <errno.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* thread_func(void* arg) {
    int result = pthread_mutex_trylock(&mutex);
    if (result == 0) {
        // 成功获取锁
        pthread_mutex_unlock(&mutex);
    } else if (result == EBUSY) {
        // 锁已被占用,处理超时情况
        printf("Failed to acquire lock, try again later.\n");
    } else {
        // 其他错误
        perror("pthread_mutex_trylock");
    }
    return NULL;
}

int main() {
    pthread_t thread1, thread2;
    pthread_create(&thread1, NULL, thread_func, NULL);
    pthread_create(&thread2, NULL, thread_func, NULL);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    return 0;
}

通过合理使用互斥锁和读写锁,并注意避免常见的并发问题,可以有效提高多线程程序的性能和稳定性。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

互斥锁-读写锁-条件锁

一,使用互斥锁 1,初始化互斥量 不能拷贝互斥量变量,但可以拷贝指向互斥量的指针,这样就可以使多个函数或线程共享互斥量来实现同步。上面动态申请的互斥量需要动态的撤销。...二,使用读写锁 通过读写锁,可以对受保护的共享资源进行并发读取和独占写入。读写锁是可以在读取或写入模式下锁定的单一实体。要修改资源,线程必须首先获取互斥写锁。...必须释放所有读锁之后,才允许使用互斥写锁。...初始化和销毁: 同互斥量一样, 在释放读写锁占用的内存之前, 需要先通过pthread_rwlock_destroy对读写锁进行清理工作, 释放由init分配的资源. 2.加锁和解锁 三,条件变量...假如某个线程需要等待系统处于某种状态下才能继续执行,Linux为了解决这种问题引入了条件变量这种线程同步对象,条件变量是用来通知共享数据状态信息的,等待条件变量总是返回锁住的互斥量,条件变量是与互斥量相关

82410

go 互斥锁和读写互斥锁

互斥锁 互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个goroutine可以访问共享资源。Go语言中使用sync包的Mutex类型来实现互斥锁。...) }() } // 等待所有goroutine执行完毕 wg.Wait() // 输出x(10000) fmt.Println(x) } 读写互斥锁...互斥锁是完全互斥的,但是有很多实际的场景下是读多写少的,当并发的去读取一个资源不涉及资源修改的时候是没有必要加锁的,这种场景下使用读写锁是更好的一种选择。...读写锁在Go语言中使用sync包中的RWMutex类型。 读写锁分为两种:读锁和写锁。...定义一个读写锁: var rwlock sync.RWMutex 加写锁: rwlock.Lock() 解写锁: rwlock.Unlock() 加读锁: rwlock.RLock() 解读锁: rwlock.RUnlock

23030
  • Golang中互斥锁和读写互斥锁

    读写互斥锁         Go语言中的读写互斥锁(RWMutex)是一种特殊类型的互斥锁,它允许多个协程同时读取某个共享资源,但在写入时必须互斥,只能有一个协程进行写操作。...相比互斥锁,读写互斥锁在高并发读的场景下可以提高并发性能,但在高并发写的场景下仍然存在性能瓶颈。         读写互斥锁有两个方法:RLock()和RUnlock()。...在写入共享资源时,需要调用Lock()方法加写锁,在写入完成后,需要调用Unlock()方法释放写锁。当有写锁或读写锁时,不能再加读锁或写锁,直到已经释放了所有锁。...读写互斥锁的示例代码 package main import ( "fmt" "sync" "time" ) var ( value int rwLock...需要注意的是,在使用读写互斥锁时,必须保证写操作只有一个,否则就会出现竞争状态,导致数据不一致的问题。同时也需要注意使用锁的力度,避免锁的范围过大,导致性能下降。

    31630

    Go语言互斥锁和读写锁

    一、互斥锁 Go语言中多个协程操作一个变量时会出现冲突的问题 go run -race 可以查看竞争 可以使用sync.Mutex对内容加锁 互斥锁的使用场景 多个goroutine访问同一个函数(代码段...) 这个函数操作一个全局变量 为了保证共享变量安全性,值合法性 使用互斥锁模拟售票窗口 package main import ( "fmt" "sync" "time" "math.../rand" ) var ( //票数 num = 100 wg sync.WaitGroup //互斥锁 mu sync.Mutex ) func sellTicker...sellTicker(2) go sellTicker(3) go sellTicker(4) wg.Wait() fmt.Println("所有票卖完") } 二、RWMutex读写锁...RWMutex可以添加多个读锁或一个写锁.读写锁不能同时存在. map在并发下读写就需要结合读写锁完成 互斥锁表示锁的代码同一时间只能有一个人goroutine运行,而读写锁表示在锁范围内数据的读写操作

    73330

    互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景

    最常用的就是互斥锁,当然还有很多种不同的锁,比如自旋锁、读写锁、乐观锁等,不同种类的锁自然适用于不同的场景。...那接下来,针对不同的应用场景,谈一谈「互斥锁、自旋锁、读写锁、乐观锁、悲观锁」的选择和使用。 互斥锁与自旋锁:谁更轻松自如?...它俩是锁的最基本处理方式,更高级的锁都会选择其中一个来实现,比如读写锁既可以选择互斥锁实现,也可以基于自旋锁实现。 读写锁:读和写还有优先级区分?...互斥锁和自旋锁都是最基本的锁,读写锁可以根据场景来选择这两种锁其中的一个进行实现。 乐观锁与悲观锁:做事的心态有何不同? 前面提到的互斥锁、自旋锁、读写锁,都是属于悲观锁。...互斥锁和自旋锁都是最基本的锁,读写锁可以根据场景来选择这两种锁其中的一个进行实现。

    1.5K40

    go 安全map 实现, 互斥锁和读写锁

    互斥锁 其中Mutex为互斥锁,Lock()加锁,Unlock()解锁,使用Lock()加锁后,便不能再次对其进行加锁,直到利用Unlock()解锁对其解锁后,才能再次加锁.适用于读写不确定场景,即读写次数没有明显的区别...启动一个线程向 map 写入值*/ go m.Display() /*启动一个线程读取 map 的值*/ var str string /*这里主要是等待线程结束*/ fmt.Scan(&str) } 读写锁...读写锁即是针对于读写操作的互斥锁。...它与普通的互斥锁最大的不同就是,它可以分别针对读操作和写操作进行锁定和解锁操作。读写锁遵循的访问控制规则与互斥锁有所不同。 在读写锁管辖的范围内,它允许任意个读操作的同时进行。...也就是说,读写锁控制下的多个写操作之间都是互斥的,并且写操作与读操作之间也都是互斥的。但是,多个读操作之间却不存在互斥关系。

    4.9K20

    Golang 读写锁RWMutex 互斥锁Mutex 源码详解

    Golang中有两种类型的锁,Mutex (互斥锁)和RWMutex(读写锁)对于这两种锁的使用这里就不多说了,本文主要侧重于从源码的角度分析这两种锁的具体实现。...如果你自己想看,我给出阅读的一个思路,可以先看读写锁,因为读写锁的实现依赖于互斥锁,并且读写锁比较简单一些,然后整理思路之后再去想一下实际的应用场景,然后再去看互斥锁。...最后别忘记还有一个互斥锁需要释放,让别的协程也可以开始抢写锁了。 至此,读写锁的分析基本上告一段落了。 针对于其中关于竞态分析的代码,有兴趣的小伙伴可以去了解一下。...互斥锁Mutex 互斥锁比读写锁复杂,但是好在golang给的注释很详细,所以也不困难(注释真的很重要)。.../// 这个互斥锁是公平锁 互斥锁有两种操作模式:正常模式和饥饿模式。

    57430

    golang并发编程之互斥锁、读写锁详解

    下面我们来看看稍微复杂一些的锁实现——读写锁。 二、读写锁 读写锁即是针对于读写操作的互斥锁。它与普通的互斥锁最大的不同就是,它可以分别针对读操作和写操作进行锁定和解锁操作。...读写锁遵循的访问控制规则与互斥锁有所不同。在读写锁管辖的范围内,它允许任意个读操作的同时进行。但是,在同一时刻,它只允许有一个写操作在进行。...也就是说,读写锁控制下的多个写操作之间都是互斥的,并且写操作与读操作之间也都是互斥的。但是,多个读操作之间却不存在互斥关系。 这样的规则对于针对同一块数据的并发读写来讲是非常贴切的。...与互斥锁类似,sync.RWMutex类型的零值就已经是立即可用的读写锁了。...请记住,针对同一个读写锁的写锁定和读锁定是互斥的。无论是写解锁还是读解锁,操作的不及时都会对使用该读写锁的流程的正常执行产生负面影响。

    64120

    如何理解互斥锁、条件变量、读写锁以及自旋锁?

    另外自从Linux 2.6版以后,mutex完全用futex的API实现了,内部系统调用的开销大大减小。...可能让其他等待条件变量的线程被唤醒了,但是此时互斥量还没解锁,从而再次陷入休眠。然而对于另外一些实现,比如Linux系统,则通过等待变形(wait morphing)解决了这一问题。...在读多写少的场景下,不加区分的使用互斥量显然是有点浪费的。此时便该上演读写锁的拿手好戏。 读写锁有一个别称叫『共享-独占锁』。...读写锁的特性: 当读写锁被加了写锁时,其他线程对该锁加读锁或者写锁都会阻塞(不是失败)。 当读写锁被加了读锁时,其他线程对该锁加写锁会阻塞,加读锁会成功。 因而适用于多读少写的场景。...所谓加读锁和加写锁,准确的说法可能是『给读写锁加读模式的锁定和加写模式的锁定』。 读写锁和互斥量一样也有trylock函数,也是以非阻塞地形式来请求锁,不会导致阻塞。

    1.5K30

    Golang并发编程之互斥锁、读写锁详解

    Golang并发编程之互斥锁、读写锁详解 谢谢慕课网cap1537老师,写的不错. 我们对Go语言所提供的与锁有关的API进行说明。这包括了互斥锁和读写锁。...我们在第6章描述过互斥锁,但却没有提到过读写锁。这两种锁对于传统的并发程序来说都是非常常用和重要的。 一、互斥锁 互斥锁是传统的并发程序对共享资源进行访问控制的主要手段。...下面我们来看看稍微复杂一些的锁实现——读写锁。 二、读写锁 读写锁即是针对于读写操作的互斥锁。它与普通的互斥锁最大的不同就是,它可以分别针对读操作和写操作进行锁定和解锁操作。...读写锁遵循的访问控制规则与互斥锁有所不同。在读写锁管辖的范围内,它允许任意个读操作的同时进行。但是,在同一时刻,它只允许有一个写操作在进行。...与互斥锁类似,sync.RWMutex类型的零值就已经是立即可用的读写锁了。

    80230

    Linux内核中的各种锁:信号量互斥锁读写锁原子锁自旋锁内存屏障等

    使用实例如下: #include linux/spinlock.h> // 定义自旋锁 spinlock_t my_lock; void my_function(void) { spin_lock...但是互斥锁不是,它的目的就是只让一个线程进入临界区,其余线程没拿到锁,就只能阻塞等待。线程互斥的进入临界区,这就是互斥锁名字由来。...另外提一下std::timed_mutex睡眠锁,它和互斥锁的区别是: 互斥锁中,没拿到锁的线程就一直阻塞等待,而睡眠锁则是设置一定的睡眠时间比如2s,线程睡眠2s,如果过了之后还没拿到锁,那就放弃拿锁...(2)))){ // do something } else{ // 没抢到 std::cout锁失败"; } 三、读写锁/抢占 — —临界区 读写锁: 用于读操作比写操作更频繁的场景,...读写锁这种就属于高阶锁了,它的实现就可以用自旋锁。 抢占: 抢占必须涉及进程上下文的切换,而中断则是涉及中断上下文的切换。

    1.6K20

    Linux线程互斥锁

    今天我们学习Linux线程互斥的话题。Linux同步和互斥是Linux线程学习的延伸。但这部分挺有难度的,请大家做好准备。那我们就正式开始了。...互斥锁 首先,我们先认识一些锁的常见接口 // 所有锁的相关操作函数都在这个头文件下 //这些函数如果又返回值,操作成功的话,返回0,失败的话。返回错误码。...锁只规定互斥访问,没有规定谁优先访问。 锁就是让多个线程公平竞争的结果,强者胜出嘛。 关于互斥锁的理解 所有的执行流都可以访问这一把锁,所以锁是一个共享资源。...为了实现互斥锁操作,大多数体系结构都提供了swap或exchange指令,该指令的作用是把寄存器和内存单元的数据相交换,由于只有一条指令,保证了原子性 。...将寄存器内的1归还给锁。然后return返回就可以了。 对互斥锁的简单封装 相信大家对互斥锁都有了充分的了解。接下来,我们就实现一下对互斥锁的简单封装。

    9410

    linux读写锁_共享内存读写锁

    一、读写锁是什么?...读写锁其实还是一种锁,是给一段临界区代码加锁,但是此加锁是在进行写操作的时候才会互斥,而在进行读的时候是可以共享的进行访问临界区的 ps:读写锁本质上是一种自旋锁 二、为什么需要读写锁?...三、读写锁的行为 读写之间是互斥的—–>读的时候写阻塞,写的时候读阻塞,而且读和写在竞争锁的时候,写会优先得到锁 四、自旋锁&挂起等待是锁?...:效率不高,很可能会使临界区的代码不被任何线程执行,因为可能会是线程被 CPU调度走了但是却没有被调度回来 五、读写锁是怎么实现?...(3)读和写之间是同步互斥关系 ps:同步---->读和写在同时竞争锁的时候,写会优先的得到锁 互斥---->读的时候写阻塞,写的时候读阻塞 4.相关函数 (1)

    6.2K11

    详解Linux多线程中互斥锁、读写锁、自旋锁、条件变量、信号量

    ---- Hello、Hello大家好,我是木荣,今天我们继续来聊一聊Linux中多线程编程中的重要知识点,详细谈谈多线程中同步和互斥机制。...*/ pthread_mutex_destroy(&mutex); return 0; } 读写锁 读写锁允许更高的并行性,也叫共享互斥锁。...互斥量要么是加锁状态,要么就是解锁状态,而且一次只有一个线程可以对其加锁。读写锁可以有3种状态:读模式下加锁状态、写模式加锁状态、不加锁状态。...()中mutex换成spin,如:pthread_spin_init() 自旋锁函数 linux中的自旋锁用结构体spinlock_t 表示,定义在include/linux/spinlock_type.h...自旋锁的接口函数全部定义在include/linux/spinlock.h头文件中,实际使用时只需includelinux/spinlock.h>即可 示例 includelinux/spinlock.h

    3.7K20

    互斥锁与读写锁:如何使用锁完成Go程同步?

    Go语言中有两种锁: 互斥锁 Mutex 读写锁 RWMutex,也叫单写多读锁 第二个锁虽然与第一个仅有两个字母差异,但其实并非同类,稍后我们会看到。名字带有一定的迷惑性,不要被它骗了。...具体讲,在Go语言中的两种锁中,普通锁Mutex是互斥锁,顾名思义这种锁就像十字路口的红绿灯,一方通行,一方停止,它会直接阻塞Go程;另一种读写锁RWMutex,这种锁是改进的立交桥版本,只阻塞Go程间的写写...如何使用加强版本的读写锁? 普通锁并不能满足所有场景的互斥需求。...在了解了Go语言的互斥锁和读写锁之后,不知道你是什么想法。是不是感觉锁非常复杂,其实除非逼不得已,不必使用锁。锁既麻烦,效率又低,在Go程同步上完败于信道。...除了信道、互斥锁与读写锁,在Go语言中用于实现微线程同步的还有Once与WaitGroup,这两者它们也是锁吗?这个问题留给你思考一下。

    1.1K10

    GO语言并发编程之互斥锁、读写锁详解

    下面我们来看看稍微复杂一些的锁实现——读写锁。 二、读写锁 读写锁即是针对于读写操作的互斥锁。它与普通的互斥锁最大的不同就是,它可以分别针对读操作和写操作进行锁定和解锁操作。...读写锁遵循的访问控制规则与互斥锁有所不同。在读写锁管辖的范围内,它允许任意个读操作的同时进行。但是,在同一时刻,它只允许有一个写操作在进行。...也就是说,读写锁控制下的多个写操作之间都是互斥的,并且写操作与读操作之间也都是互斥的。但是,多个读操作之间却不存在互斥关系。 这样的规则对于针对同一块数据的并发读写来讲是非常贴切的。...与互斥锁类似,sync.RWMutex类型的零值就已经是立即可用的读写锁了。...请记住,针对同一个读写锁的写锁定和读锁定是互斥的。无论是写解锁还是读解锁,操作的不及时都会对使用该读写锁的流程的正常执行产生负面影响。

    851110

    GO语言并发编程之互斥锁、读写锁详解

    在本节,我们对Go语言所提供的与锁有关的API进行说明。这包括了互斥锁和读写锁。我们在第6章描述过互斥锁,但却没有提到过读写锁。这两种锁对于传统的并发程序来说都是非常常用和重要的。...下面我们来看看稍微复杂一些的锁实现——读写锁。 二、读写锁 读写锁即是针对于读写操作的互斥锁。它与普通的互斥锁最大的不同就是,它可以分别针对读操作和写操作进行锁定和解锁操作。...读写锁遵循的访问控制规则与互斥锁有所不同。在读写锁管辖的范围内,它允许任意个读操作的同时进行。但是,在同一时刻,它只允许有一个写操作在进行。...与互斥锁类似,sync.RWMutex类型的零值就已经是立即可用的读写锁了。...请记住,针对同一个读写锁的写锁定和读锁定是互斥的。无论是写解锁还是读解锁,操作的不及时都会对使用该读写锁的流程的正常执行产生负面影响。

    1.2K40

    GO语言并发编程之互斥锁、读写锁详解

    在本节,我们对Go语言所提供的与锁有关的API进行说明。这包括了互斥锁和读写锁。我们在第6章描述过互斥锁,但却没有提到过读写锁。这两种锁对于传统的并发程序来说都是非常常用和重要的。...下面我们来看看稍微复杂一些的锁实现——读写锁。 二、读写锁 读写锁即是针对于读写操作的互斥锁。它与普通的互斥锁最大的不同就是,它可以分别针对读操作和写操作进行锁定和解锁操作。...读写锁遵循的访问控制规则与互斥锁有所不同。在读写锁管辖的范围内,它允许任意个读操作的同时进行。但是,在同一时刻,它只允许有一个写操作在进行。...与互斥锁类似,sync.RWMutex类型的零值就已经是立即可用的读写锁了。...请记住,针对同一个读写锁的写锁定和读锁定是互斥的。无论是写解锁还是读解锁,操作的不及时都会对使用该读写锁的流程的正常执行产生负面影响。

    849150

    GO语言并发编程之互斥锁、读写锁详解

    在本节,我们对Go语言所提供的与锁有关的API进行说明。这包括了互斥锁和读写锁。我们在第6章描述过互斥锁,但却没有提到过读写锁。这两种锁对于传统的并发程序来说都是非常常用和重要的。...下面我们来看看稍微复杂一些的锁实现——读写锁。 二、读写锁 读写锁即是针对于读写操作的互斥锁。它与普通的互斥锁最大的不同就是,它可以分别针对读操作和写操作进行锁定和解锁操作。...读写锁遵循的访问控制规则与互斥锁有所不同。在读写锁管辖的范围内,它允许任意个读操作的同时进行。但是,在同一时刻,它只允许有一个写操作在进行。...与互斥锁类似,sync.RWMutex类型的零值就已经是立即可用的读写锁了。...请记住,针对同一个读写锁的写锁定和读锁定是互斥的。无论是写解锁还是读解锁,操作的不及时都会对使用该读写锁的流程的正常执行产生负面影响。

    79050

    GO语言并发编程之互斥锁、读写锁详解

    在本节,我们对Go语言所提供的与锁有关的API进行说明。这包括了互斥锁和读写锁。我们在第6章描述过互斥锁,但却没有提到过读写锁。这两种锁对于传统的并发程序来说都是非常常用和重要的。...下面我们来看看稍微复杂一些的锁实现——读写锁。 二、读写锁 读写锁即是针对于读写操作的互斥锁。它与普通的互斥锁最大的不同就是,它可以分别针对读操作和写操作进行锁定和解锁操作。...读写锁遵循的访问控制规则与互斥锁有所不同。在读写锁管辖的范围内,它允许任意个读操作的同时进行。但是,在同一时刻,它只允许有一个写操作在进行。...与互斥锁类似,sync.RWMutex类型的零值就已经是立即可用的读写锁了。...请记住,针对同一个读写锁的写锁定和读锁定是互斥的。无论是写解锁还是读解锁,操作的不及时都会对使用该读写锁的流程的正常执行产生负面影响。

    92170
    领券