协程、线程、进程【ing】

引言:多进程和多线程的应用场景

  • 多进程健壮性:nginx杀死进程后,会自动启动新进程。

    • 通信效率较低
    • 每个进程做的事情比较独立
    • 资源隔离、安全
  • 多线程:redis6.0,提高io的性能:主线程拿到fd后,让io处理线程做数据的存取,然后主线程操作key-value,再发送给客户端。

    • 改用多进程(不同进程、虚拟内存都是独立的):不好。
    • 适用场景:
    • 多个线程之间需求协作(数据的传递)
    • 需要操作共同的对象
  • 协程

    • 定义:称为微线程,协程它不像线程和进程那样,需要进行系统内核上的上下文切换协程的上下文切换是由开发人员决定的。协程是一种用户级的轻量级线程。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。

    因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。

    • 使用原因:目前主流语言基本上都选择了多线程作为并发设施,与线程相关的概念就是抢占式多任务(Preemptive multitasking),而与协程相关的是协作式多任务。

    不管是进程还是线程,每次阻塞、切换都需要陷入系统调用(system call),先让CPU跑操作系统的调度程序,然后再由调度程序决定该跑哪一个进程(线程)。
    而且由于抢占式调度执行顺序无法确定的特点,使用线程时需要非常小心地处理同步问题,而协程完全不存在这个问题。

    因为协程是用户自己来编写调度逻辑的,对于我们的CPU来说,协程其实是单线程,所以CPU不用去考虑怎么调度、切换上下文,这就省去了CPU的切换开销,所以协程在一定程度上又好于多线程。

    • 优点

    • 无需系统内核的上下文切换,减小开销;

    • 无需原子操作锁定及同步的开销,不用担心资源共享的问题;

    • 单线程即可实现高并发,单核 CPU 即便支持上万的协程都不是问题,所以很适合用于高并发处理,尤其是在应用在网络爬虫中。

    • 缺点

    • 无法使用 CPU 的多核

      协程的本质是个单线程,它不能同时用上单个 CPU 的多个核,协程需要和进程配合才能运行在多
      CPU上。当然我们日常所编写的绝大部分应用都没有这个必要,就比如网络爬虫来说,限制爬虫的速度还有其他的因素,比如网站并发量、网速等问题都会是爬虫速度限制的因素。除非做一些密集型应用,这个时候才可能会用到多进程和协程。

    • 处处都要使用非阻塞代码

      写协程就意味着你要一值写一些非阻塞的代码,使用各种异步版本的库

  • 协程mysql和多线程mysql对照

    下图是多线程方案

    使用协程,send、recv要是用非阻塞代码,不然会导致其他写成得不到调度。协程不是不能调用linux系统系统api,而是不能使用以阻塞的方式去调用。

多线程、多进程的实现方式

  • LWP(轻量级进程)作为多线程方案
  • 纯用户空间多进程方案(协程)
  • 混合版多线程方案(前两者的混合版本)

基于 thread 的多线程开发

1. 简单使用: joindetach

/*
标准C++库中对多线程支持的声明在新的头文件中:管理线程的函数和类在 <thread> 中声明,而保护共享数据的函数和类在其他头文件中声明。
*/

#include <iostream>
#include <thread>
#include <string>

using namespace std;

void thread_one()
{
    puts("hello");
}

void thread_two(int num, string& str)
{
    cout << "num:" << num << ",name:" << str << endl;
}

int main(int argc, char* argv[])
{
    // 需要注意的是线程对象执行了join后就不再joinable了,所以只能调用join一次。
    // tt.join()是等待子线程执行完成之后,主线程才继续执行,此时主线程会释放掉执行完成后的子线程的资源。
    thread tt(thread_one);
    tt.join();  
    string str = "luck";
    // 对于线程对象yy,我们传入了调用函数的两个参数,这里在线程yy执行时,主线程不想等待子线程,故使用了yy.detach()将子线程从主线程中分离出来,这样主线程就对子线程没有控制权了,子线程执行完成后会自己释放掉资源。
    thread yy(thread_two, 88, ref(str));   //这里要注意是以引用的方式调用参数
    yy.detach();  
    return 0;
}

2. 构造函数

#include <iostream>
#include <thread>
#include <chrono>

using namespace std;

void f1(int n)
{
    for (int i = 0; i < 5; ++i)
    {
        cout << "=====Thread:" << n << "======" << endl;
        this_thread::sleep_for(chrono::microseconds(10));
    }
}

void f2(int& n)
{
    for (int i = 0; i < 5; ++i)
    {
        cout << "thread two executing" << endl;
        ++n;
        this_thread::sleep_for(chrono::microseconds(10));
    }
}

int main()
{
    int n = 0;
    thread t1;    //这是一个空的线程对象,还不是一个线程
    thread t2(f1, n + 1);
    thread t3(f2, ref(n));
    thread t4(move(t3));    //t3不再是一个线程
    t2.join();
    t4.join();
    cout << "the result n is:" << n << endl;
    return 0;
}

3. API【待补充】

4. 互斥量【待补充】

5. 同步并非操作【待补充】

例如,在第一个线程完成前,可能需要等待另一个线程执行完成。通常情况下,线程会等待一个特定事件发生,或者等待某一条件达成。这可能需要定期检查“任务完成”标识,或将类似的东西放到共享数据中,但这与理想情况差很多。 像这种情况就需要在线程中进行同步,C++标准库提供了一些工具可用于同步操作,形式上表现为条件变量 (condition variables)和期望值(futures)。并发技术规范(TS)中,为期望值添加了更多的操作,并与新的同 步工具锁存器(latches)(轻量级锁资源)和栅栏机制(barriers)一起使用。

基于协程序 Coroutines:协作式的交叉调度执行

参考

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇