一、线程的优点

1、创建一个新线程代价要比创建一个新进程小得多。在删除时也是线程代价更小。

2、切换:与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多。(不需要对cache进行切换丢弃cache(cache是寄存器和内存之间的硬件缓存),重新进行命中缓存,从“冷----->热”)

3、线程的切换虚拟内存空间依然是相同的,隐藏的耗损是上下文的切换会扰乱处理器的缓存机制,简单地说,一旦切换上下文,处理器中所有已经缓存的内存地址一瞬间都作废了,还有一个显著区别是当你改变虚拟内存空间的时候,处理的页表缓冲TLB(快表),会被全部刷新,这将导致内存的访问在一段时间内相当的低效,但是在线程的切换中,不会出现这个问题,当然还有硬件cache。

二、线程的缺点

1、性能损失

一个很少被外部事件阻塞的计算密集型线程往往无法与其他线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变。

2、健壮性降低

线程健壮性:指多线程程序抗异常、抗干扰、不出诡异 bug、崩溃概率低的能力。

健壮性降低的原因:

共享变量不加锁 / 锁使用不当

线程间通信无同步、无原子操作

锁嵌套、顺序混乱引发死锁

忽略线程中断、异常不捕获滥用全局变量、线程不安全工具类

3、缺乏访问控制

进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。

4、编程难度提高

编写与调试一个多线程程序比单线程程序困难的多。

三、线程的其他特性

线程异常

单个线程如果出现除零,野指针问题导致线程崩溃,进程也会随着崩溃。

线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随即退出。

线程用途

合理使用多线程,能提高CPU密集型程序的执行效率

合理使用多线程,能提高IO密集型程序的用户体验(比如在生活中,我们一边写代码,一边下载开发工具,就是多线程运行的一种表现)。

四、线程控制
pthread_create

用于在程序中创建一个新的线程。它的基本功能是让调用者指定一个入口函数,新线程创建后就会从该函数开始并发执行。

测试1:

#include<iostream>
#include<cstdio>
#include<string>
#include<pthread.h>
#include<unistd.h>

void *Routine(void *args)
{
    std::string name=static_cast<const char*>(args);
    while(true)
    {
        // std::cout<<"我是新线程:"<<name<<std::endl;
        printf("我是新线程:%s,tid:0x%lx\n",name.c_str(),pthread_self());
        sleep(1);
    }
}
int main()
{
    pthread_t tid;
    

    int n=pthread_create(&tid,nullptr,Routine,(void*)"thread-1");
    (void)n;
    printf("new thread id :0x%lx\n",tid);
    while(true)
    {
        std::cout<<"我是主线程...."<<std::endl;
        sleep(1);

    }
    return 0;
}

测试2:

 while(true)
    {
        // std::cout<<"我是主线程...."<<std::endl;
        printf("我是主线程tid:0x%lx\n",pthread_self());
        sleep(1);

    }

测试3:

void *Routine(void *args)
{
    std::string name=static_cast<const char*>(args);
    while(true)
    {
        // std::cout<<"我是新线程:"<<name<<std::endl;
        printf("我是新线程:%s,tid:0x%lx,pid:%d\n",name.c_str(),pthread_self(),getpid());
        sleep(1);
    }

五、线程终止

1、从线程函数return,这种方法对主线程不适用,从main函数return相当于调用exit

2、线程可以调用pthread_exit终止自己。

3、一个线程可以调用pthread_cancel终止同一进程中的另一进程。

线程等待

新线程必须被主线程等待:1、类似子进程那里的僵尸问题2、主线程要获取新线程的执行结果。

pthread_join

的作用是等待一个指定的线程结束,并回收它的资源。它相当于线程的“回收站”或“同步点”。

这里的retval它获取到的是void*routine(void*)

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐