• C++11多线程编程(常见面试题)


    【题目1】

    子线程循环 10 次,接着主线程循环 100 次,接着又回到子线程循环 10 次,接着再回到主线程又循环 100 次,如此循环50次,试写出代码

    【题解】

    首先我们来分析一下这道题...(是个刚入门的小白,分析的不好请见谅)

    1、由于子线程需要循环10次不受主线程干扰,而主线程需要循环100次不受子线程干扰,所以显然,在他们进入循环的时候需要一个锁把这段循环锁住,不然会导致资源被抢占(此处的资源可以理解为是循环里的cout)。(其实简单来说互斥量是为了保证子线程和主线程的for不同时进行

    2、然后问题来了,怎么控制子线程循环后主线程循环,然后一直这样依次循环呢?条件变量就可以做到这点,我们可以通过改变某个全局变量的值,第一次将该全局变量置为10,也就是说我们只要控制如果传入的参数和该全局变量不等,就让他一直等待,当执行完子线程的循环后改变这个全局变量为100,那么对于子线程来说全局变量和传入的参数就不相等了,那么条件变量就会一直等待。当然如果一直让他等待肯定是不对的,所以当一个线程执行完循环之后需要唤醒这个条件变量,告诉线程变量已经改变又可以开始抢资源啦。(其实条件变量就是为了控制子主线程运行的先后条件

    【代码】

    #include<thread>
    #include<iostream>
    #include<cstdio>
    #include<mutex>
    #include<condition_variable>
    using namespace std;
    int flag = 10;
    mutex mu;
    condition_variable cv;
    void fun(int x, char c)
    {
        for (int i = 0; i < 50; i++)
        {
            unique_lock<mutex> lock(mu);
            while(flag != x)
                cv.wait(lock);//在该线程阻塞之前会执行lock.unlock,这样别的线程才不会被锁住
            for (int j = 0; j < x; j++)
                cout << c << ":" << j << endl;
            flag = (x == 10)? 100 : 10;
            cv.notify_one();
        }
    }
    int main()
    {
        thread t1(fun, 10, 'A');
        fun(100, 'B');
        t1.join();
    }
    View Code

    【总结】

    理解这段代码的时候,被wait()弄了好久,可能是我太蠢qwq那么来说一下wait()吧,我们分两种情况来说。

    (1)一开始,主线程先抢到了锁

    那么就会判断flag是否等于x,很显然如果是主线程先拿到锁此时flag=10,x=100不等,那么这个时候主线程就会执行wait(),也就是会被阻塞,然后因为wait()自身有这样一个机制(当他执行的时候会自动释放锁吗,也就是会自动执行unlock,给其他线程一个拿锁的机会),这个时候子线程就会拿到锁,并且判断fag是否等于x,这时候明显是相等的,那么就会进行下面的一系列循环,这个时候重点来了,一定要改变全局变量!!如果不改变会是什么结果呢?假设我们把那句话注释掉直接执行notify_one(),那么主线程就会被唤醒它的wait()又会自动参与抢锁,由于flag没有改变,那么flag和x的值还是相等,所以它依然会被阻塞,那么依旧就是子线程执行,就不满足题意了。

    (2)一开始,子线程先抢到了锁

    因为满足flag=x,那么会执行接下来的for,按部就班改个flag,然后唤醒被wait的线程(这时候其实没有),因为执行完一个循环,uniqie_lock会自动释放锁,然后子线程和主线程就又开始抢锁了,这次我们假设还是子线程先抢到了锁,但由于修改了flag,此时flag!=x,子线程就被阻塞,然后就和情况(1)差不多啦。

    【题目2】

    编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推。

    【题解】

    其实只要理解了上一题,就是一个套路啦。这里有所不同的是有3个线程,所以最后唤醒条件变量的时候记得用notify_all()。

    【代码】

    #include<thread>
    #include<iostream>
    #include<cstdio>
    #include<mutex>
    #include<condition_variable>
    using namespace std;
    int flag = 0;
    mutex mu;
    condition_variable cv;
    void fun(int x)
    {
        for (int i = 0; i < 10; i++)
        {
            unique_lock<mutex>lock(mu);
            while (x != flag)
                cv.wait(lock);
            cout << static_cast<char>('A' + x) << " ";
            flag = (flag + 1) % 3;
            cv.notify_all();
        }
    }
    int main()
    {
        thread t1(fun, 1);
        thread t2(fun, 2);
        fun(0);
        t1.join();
        t2.join();
    }
    View Code
  • 相关阅读:
    C#实现将字符串转换成代码并执行
    Net实现钩子函数(Hook)以及通过SendMessage实现自动点击按钮和给文本框赋值
    异步与多线程的区别
    使用NODEJS实现JSONP的实例
    JS闭包作用域解析
    InterLocked学习笔记
    C#方法中的各类参数
    C# 数据类型详解以及变量、对象与内存
    通过Performance Monitor观察程序内存使用情况
    Git学习笔记(windows git之初体验)
  • 原文地址:https://www.cnblogs.com/z1014601153/p/11350631.html
Copyright © 2020-2023  润新知