线程基本概念和接口

线程相关的概念

线程概念:
1.先说进程:传统操作系统中使用PCB来描述一个程序的运行- - - PCB就是进程
2.Linux下PCB用来模拟实现线程,因此Linux下的线程是一个轻量级的进程
3.而且这些轻量级的进程因为共用大部分进程资源,相较于传统的进程更加轻量化

进程是资源分配的基本单位,线程是CPU调度的基本单位

多个PCB共用同一个虚拟地址空间,为什么不会发生调用栈混乱呢?

线程之间的独有与共享
独有:栈, 寄存器, 信号屏蔽字(阻塞的信号集合), errno(错误信息的全局变量), 线程ID, 调度优先级
共享:共享虚拟地址空间, 文件描述符, 信号处理方式,当前工作路径, 用户ID/组ID

多任务执行时,既可以用多进程,也可以用多线程,用哪个更好?
答:
在这里插入图片描述
1.需要频繁创建销毁的优先用线程
2.需要进行大量计算的优先使用线程
3.强相关的处理用线程,弱相关的处理用进程

多线程处理任务的优点
1.线程间通信除了与进程通信相同的之外还有全局数据/传参,这使得线程间通信更加方便
2.创建/销毁一个线程的成本相较于进程更低
3.线程间的调度相较于进程更少

缺点
1.线程之间缺乏访问控制,有些系统调用/异常针对的是整个进程;稳定性相较于进程更低
2.性能损失,增加了额外的同步与调度开销的同时,可用的资源不变,这时容易造成性能损失
3.编程难度高

所以像shell这种对主程序稳定安全性要求高的需要用多进程处理,让子进程处理命令,出现异常后即使子进程退出,对终端的影响也不大,但是如果用多线程,一个线程出现问题,整个进程就退出了,终端就凉凉了

线程控制

Linux中并没有提供线程的控制系统调用接口.因此有一群大佬封装了一个线程控制接口库,只用库函数创建的线程称之为用户态线程,用户态线程在内核中使用一个轻量级进程实现调度
即Linux下的线程:用户态线程+轻量级进程

线程创建

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

参数

pthread_t *thread:输出型参数,用于获取线程ID(也就是线程地址空间在虚拟地址空间的首地址)
const pthread_attr_t *attr:设置线程属性,通常置空
start_routine:线程的入口函数,返回任意类型的参数
arg:作为入口函数的实参传入
返回值:成功返回0;失败返回错误码

简单实现线程的创建,每个线程都可以运行

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

void* Ret(void *arg)
{
    while(1) {
        printf("i am same thread----%s\n", (char *)arg);
        sleep(1);
    }
    return NULL;
}
int main()
{
    //int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
    //            void *(*start_routine) (void *), void *arg);
    pthread_t tid;
    char *ret = "this is input ret";
    int ret = pthread_create(&tid, NULL, Ret, (void*)ret);
    if (ret != 0) {
        printf("pthread create error\n");//打印线程ID,为一个地址
        return -1;
    }
    printf("tid:%p\n", tid);
    while(1) {
        printf("i am main thread-----\n");
        sleep(1);
    }
    return 0;
}

注意创建多线程时,用到了封装的库,编译时默认链接的库只有lib,所以想要创建成功的话需要链接静态库(libpthread.so),所以在编译时需要这样写

gcc pthread_create.c -o create -pthread

线程中id的讨论

tid:线程地址空间首地址
pcb-->轻量级进程id
pcb-->进程id,也就是线程组id,默认等于首线程id

tid是线程id,也是线程地址空间的首地址,线程地址空间:存放着线程在用户态的描述信息,线程栈,线程的局部存储

线程终止
线程终止的三种方法:
1.从线程函数中return,但是不能从main函数中return,这样退出的是进程,会导致所有线程退出

2.调用exit终止自己,谁调用谁退出

void pthread_exit(void *retval);
其中retval是线程的退出返回值

注意: return 和 pthread_exit 返回的指针必须是全局的或者是用malloc分配的,不能再线程函数的栈上分配,因为当其他线程得到这个返回值时线程函数已经退出了

3.用pthread_cancel取消一个正在执行的线程

int pthread_cancel(pthread_t thread);
其中thread是要取消的线程ID

线程退出后,默认不会自动释放资源(保存自己的退出结果在线程独有的地址空间中),因此也会造成资源泄露
主线程退出,其他线程依然可以正常运行

线程等待
等待线程退出,获取退出线程的返回结果,释放退出线程资源
一个线程创建后,默认有一个属性 joinable ;处于joinable属性的线程退出后为了保存返回值,不会自动释放资源,需要被其他线程等待,才能释放资源,否则就会造成资源泄露

int pthread_join(pthread_t thread,void **retval);
功能:阻塞等待指定线程退出,通过retval获取返回值
其中thread是线程ID,retval指向一个指针,这个指针指向线程的返回值
返回值:成功返回0,失败返回错误码

线程分离
线程分离就是将线程的joinable属性改为detach属性
处于detach属性的线程,线程退出后将自动回收资源,所以这个线程不需要被等待

pthread_detach(pthread_t tid);

线程分离的适用场景:对线程的返回值不关心的场景
线程分离可以在任意线程中实现

### Java 多线程基本概念 #### 什么是多线程? 在Java中,多线程是指一个程序能够同时执行多个任务。每个任务被称为一个线程线程是进程中可独立调度的最小单位,在同一时间内可以并行处理多项工作[^1]。 #### 创建线程的方法 有两种主要方式用于创建新的线程: - **继承`Thread`类** 这种方法涉及定义一个新的类来扩展`java.lang.Thread`,重写其`run()`方法以包含要在线程内执行的操作逻辑。之后实例化该自定义线程对象并通过调用它的`start()`启动它。 - **实现`Runnable`接口** 更推荐的做法是从现有类外部提供实现了`Runnable`接口的对象给标准的`Thread`构造函数。这样做不仅绕过了单一继承带来的限制,还允许更方便地共享资源或状态信息[^2]。 ```java // 使用Runnable接口的例子 public class MyTask implements Runnable { @Override public void run() { System.out.println("My task is running."); } public static void main(String[] args) { Thread thread = new Thread(new MyTask()); thread.start(); } } ``` 对于更加复杂的场景,还可以考虑使用`Callable<V>`接口配合`Future<T>`机制获取返回结果以及支持异常传播等功能。 #### 线程的状态转换 线程在其生命周期中有几种不同的状态:新建(New),就绪(Runnable),运行(Running),阻塞(Blocked),等待(Waiting),计时等待(Timed Waiting),终止(Terminated)[^3]。这些状态反映了线程当前所处的位置及其活动状况。 #### 同步与锁机制 由于多个线程可能访问相同的内存区域,因此同步成为必要措施之一,用来防止竞争条件的发生。可以通过`synchronized`关键字或者显式的锁定原语如ReentrantLock来进行控制。 #### 守护线程 vs 用户线程 Java中的线程分为两种类型——用户线程守护线程。前者通常代表应用程序的主要业务流程;后者则负责辅助性质的工作比如垃圾回收(GC)等服务型功能。一旦所有的非守护(即用户)线程结束,则整个虚拟机将会关闭,即使还有存活的守护线程也不会继续存在。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值