多线程这些都不清楚,你面试?还不赶紧看看?细到恐怖....

并行和并发的区别:

1.并发(concurrency):在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。

并发是指同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上有多个进程被同时执行的效果–宏观上并行,针对单核处理器

其中两种并发关系分别是同步和互斥。
  • 互斥:进程间相互排斥的使用临界资源的现象,就叫互斥。
  • 同步(synchronous):进程之间的关系不是相互排斥临界资源的关系,而是相互依赖的关系。

进一步的说明:就是前一个进程的输出作为后一个进程的输入,当第一个进程没有输出时第二个进程必须等待。具有同步关系的一组并发进程相互发送的信息称为消息或事件。(彼此有依赖关系的调用不应该同时发生,而同步就是阻止那些“同时发生”的事情
其中并发又有伪并发和真并发,伪并发是指单核处理器的并发,真并发是指多核处理器的并发。

2.并行(parallelism):在单处理器中多道程序设计系统中,进程被交替执行,表现出一种并发的外部特种;在多处理器系统中,进程不仅可以交替执行,而且可以重叠执行。在多处理器上的程序才可实现并行处理。

从而可知,并行是针对多处理器而言的。并行是同时发生的多个并发事件,具有并发的含义,但并发不一定并行,也亦是说并发事件之间不一定要同一时刻发生。(同一时刻,有多条指令在多个处理器上同时执行–针对多核处理器)

同步和异步的区别:

  • 同步(synchronous):进程之间的关系不是相互排斥临界资源的关系,而是相互依赖的关系。进一步的说明:就是前一个进程的输出作为后一个进程的输入,当第一个进程没有输出时第二个进程必须等待。具有同步关系的一组并发进程相互发送的信息称为消息或事件。
  • 异步(asynchronous):异步和同步是相对的,同步就是顺序执行,执行完一个再执行下一个,需要等待、协调运行。异步就是彼此独立,在等待某事件的过程中继续做自己的事,不需要等待这一事件完成后再工作。
    线程就是实现异步的一个方式。异步是让调用方法的主线程不需要同步等待另一线程的完成,从而可以让主线程干其它的事情。

1、线程的概念:

线程是进程的一条执行流,是cpu调度的基本单位,一个进程可以有多个线程;线程是进程中的一条执行流,是CPU调度的基本单位,一个进程中可以有多个线程;
Linux下的线程执行流是通过pcb实现的,且一个进程中可能有多个pcb,并且这些pcb共享同一个进程中的大部分资源,因此,也被称为轻量级进程;

  • LWP:light weight process 轻量级的进程,本质仍是进程(在Linux环境下)
  • 进程:独立地址空间,拥有PCB
  • 线程:也有PCB,但没有独立的地址空间(共享)
  • 区别:在于是否共享地址空间。 独居(进程);合租(线程)。

Linux下:
线程:最小的执行单位,调度的基本单位。
进程:资源分配的基本单位,可看成是只有一个线程的进程。

1.2.线程之间的独有与共享

  • 共享:虚拟地址的空间(代码段、数据段、堆…)、文件描述符、信号处理方式、工作路径…
  • 独有:线程栈、寄存器、信号屏蔽字、优先级、errno、线程标识符ID…

1.3 多进程与多线程多任务处理优缺点分析

共同优点:

  • 在CPU资源足够的情况下都可以实现并行的任务处理,提高效率;
  • IO密集型程序(程序中进行大量的IO操作,对CPU资源要求不高)中,同时发起IO操作减少IO阻塞时间;
  • CPU密集型程序(程序中进行大量的数据运算,对CPU资源要求高)中,执行流的数量并不是越多越好,多了反而会增加调度成本;

多线程进行多任务

线程优点:

(1)共享虚拟地址空间,因此线程间通信更加灵活(还可以通过全局变量、函数传参来实现通信);

(2)线程的创建和销毁成本更低;

(3)同一个进程中的线程调度切换成本更低;

线程缺点:
健壮性低,有些调用和异常是针对整个进程产生的;

例如:exit接口,进程退出会使进程中的所有线程都退出;

大多数情况下,使用多线程,在稳定性要求高的场景中使用多进程;

进程优点:
稳定、健壮性高。(异常导致进程退出,所有线程退出,但不影响其他进程)–主进程安全性要求高的场景–比如:shell、服务器。

2.线程控制(创建、退出、等待、分离)

linux并没有向上提供用于创建线程的接口。大佬们对系统调用接口进行封装实现了上层用户态的线程控制接口;

  • 我们操作线程的接口都是库函数,需要引入头文件<pthread.h>;
  • 链接这些线程函数库时要使用编译器命令的"-lpthread"选项

2.1.创建线程

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

返回值:成功返回0;失败返回非0;
在这里插入图片描述

  • thread:用于获取线程ID;

  • attr:设置线程属性,设置为NULL,表示默认属性;

  • start_routine:线程的入口函数;

  • arg:通过线程入口函数给线程传递的参数;

2.2 线程终止

  • 线程入口函数中执行return(线程入口函数运行完毕,线程退出,);
  • 调用pthread_exit终止自己;
  • 调用pthread_cancel终止同一进程中的另一个线程;
 void pthread_exit(void *retval);
 //retcal:返回值
 //可以在任意位置,哪个线程调用哪个线程退出;

在这里插入图片描述

 int pthread_cancel(pthread_t thread);//被动退出
 //thread:一个指定的线程ID
 //传入谁的ID谁退出;
//返回值:成功返回0,失败返回非0;

在这里插入图片描述注意主线程退出并不会导致进程退出,只有所有线程退出了进程才会退出;

代码实现

//代码实现:linux下
#include <stdio.h>
#include <pthread.h>

void *thr_entry(void *arg)
{
    printf("%s\n", (char*)arg);
    while(1) {
        printf(" i am normal thread-%p-%d\n", pthread_self(), getpid());
        sleep(1);
        pthread_exit(NULL);
    }
    return NULL;
}
int main ()
{
    pthread_t tid;
    int ret;
    char *ptr = "今天的天气好晴朗\n";
    pthread_create(获取ID, 属性, 入口函数, 传入参数)
    ret = pthread_create(&tid, NULL, thr_entry, (void*)ptr);
    if (ret != 0) {
        printf("pthread_create failed!\n");
        return -1;
    }
    sleep(2);
    pthread_cancel(tid);
    while(1) {
        printf("i am main thread--%p-%d\n", pthread_self(), getpid());
        sleep(1);
    }
    return 0;
}

2.3.线程等待

线程默认情况下退出后,资源不会被回收,需要被其他线程等待,获取退出线程的返回值释放资源。

线程也不是必须被等待,在线程属性中,有一个分离属性,默认是joinable,处于joinable状态的线程退出后不会自动释放资源,需要被等待;

在这里插入图片描述

int pthread_join(pthread_t thread, void **retval);
//thread:线程ID
//**retval:	返回值
//pthread_join是一个阻塞接口
//返回值:成功返回0,失败返回错误码

在这里插入图片描述

代码实现

//代码实现,linux
 #include<stdio.h>
  2 #include<pthread.h>
  3 void* thr_entry(void* arg)
  4 {
  5 char *ptr="hello pthread\n";
  6//
  7 sleep(3);
  8 return (void*)ptr;
  9 
 10 }
 11 int main(int argc,int *argv[])
 12 {
 13         pthread_t tid;
 14         int ret=pthread_create(&tid,NULL,thr_entry,NULL);
 15         if(ret!=0)
 16         {
 17         printf("thread create error\n");
 18         return -1;
 19         }
 20 
 21         //pthread_join(线程id,获取返回值)
 22         void *retval=NULL;
 23         pthread_join(tid,&retval);
 24         printf("retval:%s\n",retval);
 25         while(1)
 26         {
 27         printf("main thread\n");
 28         sleep(1);
 29         }
 30         return 0;
 31 
 32 }
     

2.4 线程分离
如果你对一个线程的返回值不关心,你也不想去等待这个线程的推出;
设置线程分离属性为detach属性,处于detach属性的线程退出后自动释放资源,不需要被等待;

int pthread_detach(pthread_t thread);
//pthrad:分离线程的id
//可以在任意位置;

在这里插入图片描述

pthread_detach(pthread_self()); 
//pthread_self()函数,获取调用函数id;见下图:
// 线程自己分离

在这里插入图片描述

如果不知道,man函数里的左上角()中的数字代表什么,请看上一篇博客;
https://blog.csdn.net/weixin_52270223/article/details/115710222?spm=1001.2014.3001.5501

线程安全等问题清见下一篇博客;**
如有错误或者补充,评论下;互相学习,互关一波,抱拳了

  • 12
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
使用多线程技术编程可以带来以下好处: 1. 提高程序的响应速度和吞吐量:多线程可以将复杂的任务分解成多个子任务,使得程序可以同时处理多个任务,从而提高程序的响应速度和吞吐量。 2. 提高系统的资源利用率:多线程可以利用多核 CPU 的优势,让程序更好地利用系统资源,从而提高系统的资源利用率。 3. 改善用户体验:多线程可以使得程序在进行复杂计算的同时,还能够及时响应用户的输入,改善用户体验。 4. 降低程序的复杂度:多线程可以让程序结构更加清晰,使得代码的可读性和可维护性都得到提高。 5. 实现并发编程:多线程可以方便地实现并发编程,从而更好地应对高并发场景,比如服务器应用、网络通信等。 多线程应用场景包括但不限于以下五个: 1. 处理大量数据:多线程可以将数据分成多个部分,分别交给不同的线程处理,从而加快数据处理速度。 2. 图像处理:图像处理需要大量的计算量,多线程可以将图像分成多个部分,分别交给不同的线程处理,从而加快图像处理速度。 3. 服务器应用:服务器需要同时处理多个客户端请求,多线程可以让服务器同时处理多个请求,提高服务器的响应速度。 4. 游戏开发:游戏需要同时处理多个事件,比如玩家的输入、游戏逻辑的计算等,多线程可以让游戏同时处理多个事件,提高游戏的性能和体验。 5. 网络通信:网络通信需要同时处理多个连接和请求,多线程可以让程序同时处理多个连接和请求,提高网络通信的性能和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值