多线程-数据共享问题(代码片段)

zhiminzeng zhiminzeng     2022-11-30     474

关键词:

一、基本概念

1、互斥量(mutex)

互斥量:是个类对象(可以理解为一把锁),多个线程尝试用lock()成员函数来加锁这把锁,只有一个线程能锁定成功(成功的标志是lock()函数能够返回,返回不了说明没有锁成功)

2、死锁

死锁:一般是两个或两个以上的互斥量,在两个或多个地方上锁的顺序不一致导致的互相等待的情况

死锁解决方法:保证每个地方,互斥量上锁的顺序一致

二、样例

1、多线程加锁的例子

class MyClass  // 模拟给一个消息队列发消息和处理消息
public:
    void WriteMessage() // 模拟发消息,也就是往消息队列中写
    
        for (int i = 0; i < 10000; ++i)
        
            cout << "插入一个元素:" << i << endl;
            m_mutex.lock();    // lock() 与 unlock() 要成对使用
            m_messages.push_back(i);
            m_mutex.unlock();
        
    

    //void ReadMessage()   // 模拟处理消息队列中的消息,从中读,也删除
    //
    //    for (int i = 0; i < 10000; ++i)
    //    
    //        if (!m_messages.empty())   // 用到共享数据m_messages 的地方都要加锁
    //        
    //            int i = m_messages.front();  // 用到共享数据m_messages 的地方都要加锁
    //            cout << "读取的数据为:" << i << endl;   // 此处不需要加锁,只加锁需要加锁的部分,提高程序效率
    //            m_messages.pop_front();   // 用到共享数据m_messages 的地方都要加锁
    //        
    //        else
    //        
    //            cout << "目前消息队列为空" << i << endl;
    //        
    //    
    //

    // 上面的函数优化后的结果
    // 把需要加锁的代码专门提取出来
    // 只对需要加锁的代码加锁,操作共享数据的部分
    bool IsMessagesListEmpty(int& iCount)
    
        m_mutex.lock();
        if(!m_messages.empty()) 
        
            iCount = m_messages.front(); 
            m_messages.pop_front(); 
            m_mutex.unlock();   // 每条分支语句都要unlock
            return true;
        
        m_mutex.unlock();  // 每条分支语句都要unlock
        return false;
    

    void ReadMessage()   // 模拟处理消息队列中的消息,从中读,也删除
    
        int iCount = 0;
        for (int i = 0; i < 10000; ++i)
        
            if (IsMessagesListEmpty(i))
            
                cout << "读取的数据为:" << i << endl;
            
            else
            
                cout << "目前消息队列为空" << i << endl;
            
        
    

private:
    list<int> m_messages;   // 模拟消息队列
    mutex m_mutex;   // 创建一个互斥量成员对象
;

int main()

    MyClass ele;
    std::thread writeThread(&MyClass::WriteMessage, &ele);  // 
    std::thread readThread(&MyClass::ReadMessage, &ele);    // 
    readThread.join();
    writeThread.join();

    cout << "主线程" << endl;
    system("pause");
    return 0;

2、lock_guard

//std::lock_guard 相当于lock和unlock
std::lock_guard<std::mutex> myLockGuard(m_mutex);
// myLockGuard构造的时候执行mutex::lock
// myLockGuard析构的时候执行mutex::unlock
// 可以通过加  来控制lock_guard 的生存周期,从而达到随时加锁,随时解锁的目的

3、std::lock

// 解决死锁的方法,保证上锁的顺序一致
// 也可以用std::lock() 来对多个锁进行加锁
// std::lock() 可以同时锁住两个或两个以上的互斥量
// 它不存在在多线程中,因为锁的顺序问题,而导致的死锁问题
// 要么其中的互斥量都锁住,要么都没锁住,不会锁住其中一个,而去等另外一个
// 也就是说,如果其中有一个锁已经被锁住了,它需要等所有的锁都能上锁的状态,才能加锁,继续往下执行
// 示例:
std::lock(m_mutex1, m_mutex2)  // 上锁一起上
m_mutex1.unlock();   // 解锁还是需要自己解锁
m_mutex2.unlock();

4、结合std::lock() 和lock_guard 

// 结合lock_guard 和 std::lock 达到不需要手动unlock() 的效果
std::lock(m_mutex1, m_mutex2)
std::lock_guard<std::mutex> myLockGuard(m_mutex1, std::adopt_lock);
std::lock_guard<std::mutex> myLockGuard(m_mutex2, std::adopt_lock);
// std::adopt_lock 的作用是让 lock_guard 在构造的时候,不执行lock()
// 因为在std::lock()中已经执行了lock()

 

多线程安全问题(代码片段)

多线程访问共享数据会产生安全问题,比如下面的案例,创建了三个线程,访问共享的数据,会出现安全问题Runable实现类当ticket的值大于0,run方法里输出ticket的值packagecn.zhuobo.day12.aboutMultithreading;publicclassRunableImplimplementsRunnablepr... 查看详情

线程安全(代码片段)

1、线程安全:多线程单线程程序运行结果一致线程不安全:多线程单线程程序运行结果不一致2、导致线程安全问题原因全局变量或者静态变量引起;一般情况下,多个线程只读数据,不写数据,则线程是安全的;若多个线程同... 查看详情

多线程共享数据(代码片段)

 多个线程行为一致共同操作一个数据,最经典的例子就是卖票publicclassShareDataprivateintnum=10;publicsynchronizedvoidinc()num++;System.out.println(Thread.currentThread().getName()+"调用inc这个方法num="+num);tryThread.sleep(1000) 查看详情

java多线程编程——多线程技能(代码片段)

第一章Java多线程技能文章目录第一章Java多线程技能前言一、进程和多线程概述二、使用多线程1.继承Thread类2.线程随机性的展现3.实现Runnable接口4.使用Runnable接口实现多线程的优点5.实例变量共享造成的非线程安全问题与解决方... 查看详情

线程的同步(解决多线程安全问题)(代码片段)

多线程出现安全问题的原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有 执行完,另一个线程参与进来执行。导致共享数据的错误。 解决方法: 对多条操作共... 查看详情

高并发多线程基础之线程间通信与数据共享及其应用(代码片段)

前言本篇文章主要介绍的是java多线程之间如何通信,协同处理任务,以及数据共享,定时任务处理等操作。多线程之间通信的方式在实际开发过程中多个线程同时操作,有两种情况的,数据共享和线程间协作... 查看详情

rust多线程之数据共享(代码片段)

1.怎么创建线程我们都知道Java中通过实现Runnable接口或继承Thread类,来完成一个线程的创建,那么在Rust中是如何实现一个线程的呢?代码如下。fnhow_to_create_a_thread() //创建一个线程letthread_handle=thread::spawn(||println!(... 查看详情

个人笔记--多线程(安全和通信)(代码片段)

线程安全问题:由于多个线程在操作共享数据,且多条语句对共享数据进行运算,所以产生了多线程安全问题,从而有了同步代码块。同步的前提:至少两个线程。必须保证是使用同一个锁。补充:多次start()同一个线程是非法... 查看详情

多线程(代码片段)

1线程同步1.1线程安全  java允许多线程并发控制,当多个线程同时操作一个可共享资源变量时(如对其进行增删改查操作),会导致数据不准确,而且相互之间产生冲突。所以加入同步锁以避免该线程在没有操作完共享资源前... 查看详情

多线程安全问题

------------恢复内容开始------------一、线程中安全问题产生的原因。1、多个线程在操作共享数据。2、操作共享数据的线程代码有多条。当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全... 查看详情

从零开始学java-day17(代码片段)

多线程编程的两种实现方式extendsThread优点:缺点:后续变化小,局限性大implementRunnable优点:多实现,更加灵活且解耦缺点:写法相对复杂,一些资源需要借助Thread多线程数据安全隐患怎么产生?线程的随机性+访问延迟以后如... 查看详情

java多线程编程——多线程技能(代码片段)

第一章Java多线程技能文章目录第一章Java多线程技能前言一、进程和多线程概述二、使用多线程1.继承Thread类2.线程随机性的展现3.实现Runnable接口4.使用Runnable接口实现多线程的优点5.实例变量共享造成的非线程安全问题与解决方... 查看详情

线程同步机制。(代码片段)

---恢复内容开始---线程安全问题:概述:场景:电影院有一百张票,现在用一个窗口卖1-100号票,属于单线程问题,无线程安全问题      现在有两个窗口,分别卖1-50和51-100号票,属于多线程问题,因为没有访问共享数 ... 查看详情

7.2.4-并发多线程互斥锁(代码片段)

一互斥锁进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,而共享带来的是竞争,竞争带来的结果就是错乱,如下frommultiprocessingimportProcess,Lockimporttimedeftask(name):print("%s1"%name)time... 查看详情

java面试题多线程-线程安全(代码片段)

面试题:Java是如何解决线程安全问题的,有几种方式?并对比几种方式的不同方式一:同步代码块synchronized(同步监视器=对象)//需要被同步的代码说明:操作共享数据的代码,即为需要被同步的代码。--... 查看详情

线程数据共享和安全-threadlocal(代码片段)

ThreadLocal线程数据共享和安全-ThreadLocal概述代码示例源码分析大家好呀,我是小笙!这部分是我学习ThreadLocal的笔记线程数据共享和安全-ThreadLocal概述ThreadLocal是一个将在多线程中为每一个线程创建单独的变量副本的类;当... 查看详情

python多进程和多线程的使用(代码片段)

...参数args和kwargs5.进程之间不共享全局变量6.守护进程7.多线程7.1线程介绍7.2多线程实现方式8.线程的无序执行9.守护线程10.线程之间共享全局变量11.线程共享全局变量出现的问题12.线程同步13.互斥锁14.解释一下互斥锁产生的死锁问... 查看详情

多线程(代码片段)

1.进程VS线程2.创建多线程-threading3.创建多线程-Thread子类4.同步5.死锁6.生产者与消费者模式  1.进程VS线程定义进程是资源分配的最小单位,线程是CPU调度的最小单位。一个程序启动后至少有一个进程,一个进程至少有一个... 查看详情