C++&&QT基础多线程总结

转自

https://blog.csdn.net/czyt1988/article/details/64441443/            //好的学习文章

如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

好比你有两个一模一样的银行卡(账户一样,余额一样,当然现实中是没有的),假如卡上余额1000块,而你跟你女朋友同时在不同的ATM上面取1000块钱(是同时哦,理想中的同时),如果线程不安全,那么俩人都能同时取出1000块(赚死了)。而如果线程安全的话,只能一个人同时操作一个账户,当这个账户正在被操作时,是被锁起来的,不给别人动的,只能你自己动,你动完了别人才能动。

3.为什么会有线程安全问题?

线程安全问题都是由全局变量静态变量引起的。

若每个线程中对全局变量静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

安全性:

扫描二维码关注公众号,回复: 11589839 查看本文章

比如一个 ArrayList 类,在添加一个元素的时候,它可能会有两步来完成:1. 在 Items[Size] 的位置存放此元素;2. 增大 Size 的值。

单线程运行的情况下,如果 Size = 0,添加一个元素后,此元素在位置 0,而且 Size=1;

而如果是在多线程情况下,比如有两个线程,线程 A 先将元素存放在位置 0。但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B也向此 ArrayList 添加元素,因为此时 Size 仍然等于 0 (注意哦,我们假设的是添加一个元素是要两个步骤哦,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加 Size 的值。

那好,我们来看看 ArrayList 的情况,元素实际上只有一个,存放在位置 0,而 Size 却等于 2。这就是“线程不安全”了

QProcess :进程

QThread:线程

QT中创建线程 一般子类化QThread 然后重写run函数

thread.start() 开始一个线程 默认调用run函数

thread.stop中止一个线程

继承自QThread的子类 thread中的函数 只有run这个函数的内容是在创建出来的新的线程里 其他函数还是在原来的线程里。

通过上面的测试,我们在使用线程的时候,就可以将一个类派生自QObject,然后实现所有的signal/slot,然后通过调用movetothread函数来使他们执行在新的线程里面,而不是每次都要重新派生QThread,并且派生QThread函数的另外一个不好的地方是只有run函数内部的代码才会执行在新线程里面,相比起来,派生QObject并使用movetothread函数更具有灵活性。

标准多线程生产者和消费者的示例

std::list<std::string>       packet_str_vec; //解完包后的string_vec
std::mutex                      m_mutex;        //锁    
std::condition_variable   m_cvItems;      //条件变量

生产者:

void Net::NetTastHandle::AddPacketVec(std::string packet_str)
{
    std::unique_lock<std::mutex> guard(m_mutex);//上锁
       packet_str_vec.push_back(packet_str);
       m_cvItems.notify_all();
}

消费者:

void NetTastHandle::Run()
{
    while (!stop_flag)
    {
        std::unique_lock<std::mutex> guard(m_mutex);//上锁(保护条件变量和list组)

        while (packet_str_vec.empty())              //防止线程虚假唤醒
        {
            //如果获得了互斥锁,但是条件不合适的话,pthread_cond_wait会释放锁,不往下执行。
            //当发生变化后,条件合适,pthread_cond_wait将直接获得锁。

            m_cvItems.wait(guard);                  //条件变量
        }

        string cur_str = packet_str_vec.front();  
        packet_str_vec.pop_front();               //删除栈首
        //进一步解包。。。。
        HandlePacket(cur_str);
    }
}

锁只是保护代码端不被其他线程访问。每个线程都竞争这个锁,竞争到了就可以执行我们让他执行的代码,这样就可以控制线程读写之间的次序。

猜你喜欢

转载自blog.csdn.net/qq_36533978/article/details/82892316
今日推荐