C++ 多线程练习题 以及知识点

转载:一些c++多线程习题 - geloutingyu - 博客园 (cnblogs.com)

知识点:

this_thread::yield(); //当前线程放弃执行,操作系统调度另一线程继续执行

ifstream in(fileName);            //ifstream 是针对文件读取的流
ofstream out(fileName, ios::app); //ofstream 是针对文件写入的流

文件流对象有两个可用于随机文件访问的成员函数:tellp 和 tellg
tellp 用于返回写入位置,tellg 则用于返回读取位置

自己手写练习才有感觉:

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

方法一:采用this_thread::yield();

#include 
#include 
using namespace std;

const int countNum = 50;
int flag = 10;
mutex mu;

void fun(int num,string_view str)
{
    for (int i=0;i< countNum;++i)
    {
        while (num != flag)
        {
            this_thread::yield(); //当前线程放弃执行,操作系统调度另一线程继续执行
        }
        lock_guard lock(mu);
        for (int j=0;j

总结:fun(100, "father");要放在join之间,子线程A先于函数执行前创建了,主要是要让主线程先跑起来,this_thread::yield();使当前线程停止,让另外线程启动。

方法二:采用条件变量condition_variable

#include 
#include 
using namespace std;

const int countNum = 50;
int flag = 10;
condition_variable cv;
mutex mu;

void fun(int num,string_view str)
{
    for (int i=0;i< countNum;++i)
    {     
        unique_lock lock(mu);  
        cv.wait(lock, [&]{return num == flag; });
        for (int j=0;j

总结:condition_variable 只能和unique_lock搭配使用,原因可以看C++11:为什么 std::condition_variable 使用 std::unique_lock? - IT工具网 (coder.work)。

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

方法一:采用this_thread::yield();

C++ 多线程练习题 以及知识点_第1张图片

 方法二:采用条件变量condition_variable

C++ 多线程练习题 以及知识点_第2张图片

 总结:注意cv.wait 中填写的条件是 如果为真则执行接下来的代码。

第三题:(google笔试题):有四个线程1、2、3、4。线程 1 的功能就是输出1,线程2的功能就是输出2,以此类推.........现在有四个文件ABCD。初始都为空。现要让四个文件呈如下格式:

A:1 2 3 4 1 2....

B:2 3 4 1 2 3....

C:3 4 1 2 3 4....

D:4 1 2 3 4 1....

#include 
#include 
#include 
#include 
using namespace std;
mutex mu;
condition_variable cv;
const string fileName = "D://vsTest//BeStrong//txt//strong_";

ofstream f0(fileName+"A.txt");
ofstream f1(fileName + "B.txt");
ofstream f2(fileName + "C.txt");
ofstream f3(fileName + "D.txt");

ofstream* file[4];
int v[] = {4,1,2,3};
int a =0, b = 0, c = 0, d = 0;
void fun(int x,int num)
{
   while (num--)
   {
       for (int i=0;i<4;i++)
       {
           unique_lock lock(mu);
           if (x==1)
           {
               cv.wait(lock, [&] { return v[i] == 4; });
               (*file[i]) << 1;
               v[i] = 1;
               a++;
               lock.unlock();
               cv.notify_all();
              
           }
           else if (x == 2)
           {
               cv.wait(lock, [&] { return v[i] == 1; });
               (*file[i]) << 2;
               v[i] = 2;
               b++;
               lock.unlock();
               cv.notify_all();
           }
           else if (x == 3)
           {
               cv.wait(lock, [&] { return v[i] == 2; });
               (*file[i]) << 3;
               v[i] = 3;
               c++;
               lock.unlock();
              
               cv.notify_all();
           }
           else
           {
               cv.wait(lock, [&] { return v[i] == 3; });
               (*file[i]) << 4;             
               v[i] = 4;
               d++;
               lock.unlock();
               cv.notify_all();
           }
       }
   }
}

int main()
{
    file[0] = &f0;
    file[1] = &f1;
    file[2] = &f2;
    file[3] = &f3;
    thread t0(fun,1,10);
    thread t1(fun, 2, 10);
    thread t2(fun, 3, 10);
    fun(4,10);
    t0.join();
    t1.join();
    t2.join();

    for (size_t i = 0; i < 4; i++)
    {
        file[i]->close();
    }
    return 0;
}

C++ 多线程练习题 以及知识点_第3张图片

 总结:我在每个线程中放了一个变量,原本以为每个变量应该是只差1,查看结果如图,说明线程并不是顺序执行的,即使用条件变量,这本来就是线程的特点,随机性。但结果是顺序。这就是多线程并发的优势。

第四题:有一个写者很多读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者读时写者也不能写

#include 
#include 
#include 
#include 
using namespace std;
mutex mu;
condition_variable cv;
const string fileName = "D://vsTest//BeStrong//txt//strong_A.txt";

ifstream in(fileName);            //ifstream 是针对文件读取的流
ofstream out(fileName, ios::app); //ofstream 是针对文件写入的流

int cnt = 0;
void write()
{
    char ch;
    while (true)
    {
        unique_lock lock(mu);
        ch = getchar();
        out << ch;
        ++cnt;
        lock.unlock();
        cv.notify_all();
    }
}

void read()
{
    char ch;
    while (true)
    {
        unique_lock lock(mu);
        cv.wait(lock, [&] { return cnt>0; });
        in >> ch;
        cout << "cout:" << ch << endl;
        --cnt;
    }
}

int main()
{
    cnt = in.tellg();//文件流对象有两个可用于随机文件访问的成员函数:tellp 和 tellg
                     //tellp 用于返回写入位置,tellg 则用于返回读取位置
    thread w(write);
    thread r0(read);
    thread r1(read);
    thread r2(read);

    w.join();
    r0.join();
    r1.join();
    r2.join();
    in.close();
    out.close();
    return 0;
}

第四题:STL 中的 queue 是非线程安全的,一个组合操作:front();  pop() 先读取队首元素然后删除队首元素,若是有多个线程执行这个组合操作的话,可能会发生执行序列交替执行,导致一些意想不到的行为。因此需要重新设计线程安全的 queue 的接口

#include 
#include 
#include 
#include 
#include 
using namespace std;

template
class thread_safe_queue {
private:
    mutex mu;
    condition_variable cv;
    queue que;

public:
    thread_safe_queue() = default;
    ~thread_safe_queue() = default;
    thread_safe_queue(const queue& q) :que(q) {}
    thread_safe_queue(const thread_safe_queue& tsq){
        std::unique_lock lock(mu);
        que = tsq;
    }

    void push(const T &data)
    {
        std::unique_lock lock(mu);
        que.push(data);
        cout << "push:" << data << endl;
        lock.unlock();
        cv.notify_all();
    }

    T pop(void)
    {
        std::unique_lock lock(mu);
        cv.wait(lock, [&] {return !que.empty(); });
        T value = que.front();
        que.pop();
        return value;
    }

    bool empty(void)
    {
        std::unique_lock lock(mu);
        return que.empty();
    }
};

thread_safe_queue q;
mutex mu;

int main()
{
    auto push_value = [&] {
        for (int i=0;i<100;++i)
        {
            q.push(i);
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
            //this_thread::yield(); //降低cpu使用率,死循环cpu占用很高的
        }
    };
    auto pop_value = [&] {
        while (true)
        {
            while (!q.empty())
            {
                std::unique_lock lock(mu);
                cout <<"pop:"<< q.pop() << endl;
            }
        }
    };
    thread pushT(push_value);
    thread popT0(pop_value);
    thread popT1(pop_value);

    pushT.join();
    popT0.join();
    popT1.join();
    return 0;
}

总结:

通常来说使用sleep。

 std::this_thread::sleep_for(std::chrono::milliseconds(1));
this_thread::yield(); //降低cpu使用率,死循环cpu占用很高的

两种效果不一样:

C++ 多线程练习题 以及知识点_第4张图片

 C++ 多线程练习题 以及知识点_第5张图片

你可能感兴趣的:(多线程,c++)