[Linux]线程概念和创建

本文详细介绍了线程在Linux中的实现原理,强调了进程与线程的区别,探讨了线程ID的作用,以及如何使用POSIX线程库创建、控制和分离线程。还涉及了`clone`系统调用和线程地址空间布局的概念。

线程概念:

线程:是进程内的一个执行分支。线程的执行颗粒度,比进程要细。
1.在Linux中,线程在进程的"内部"执行,线程在进程的地址空间内运行。
2.在Linux中,线程的执行粒度要比进程更细,因为线程执行的是进程代码的一部分。
在这里插入图片描述
(在Linux中没有真正意义上的线程,而是用"进程"模拟的线程。复用进程数据结构和管理算法)
CPU:线程 <= 执行流 <= 进程

重新定义进程和线程

什么叫做线程? 线程是操作系统调度的基本单位
重新理解进程?内核观点,进程是承担分配系统资源的基本实体
线程是进程内部的执行流资源。
进程是资源分配的基本单位。
线程是调度的基本单位。
线程共享进程数据,但也拥有自己的一部分数据:
1.线程ID
2.一组寄存器
3.栈
4.errno
5.信号屏蔽字
6.调度优先级
在这里插入图片描述
线程比进程要更轻量化(为什么?):
a.创建和释放更加轻量化
b.切换更加轻量化
(整个生命周期,cpu中cache缓冲的热数据,线程内的切换,不需要cache数据)

POSIX线程库

与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的
要使用这些函数库,要通过引入头文<pthread.h>
链接这些线程函数库时要使用编译器命令的“-lpthread”选项

创建一个新线程:

int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void (start_routine)(void), void arg);
pthread_t(无符号长整数):输出型参数,用于存储新创建线程的线程 ID。
pthread_attr_t:线程的属性,设置为nullptr,则使用默认属性
void *(start_routine)(void):函数指针
arg:指向将在创建新线程时传递给 start_routine 函数的参数。( 创建线程成功,新线程回调线程函数的时候,需要参数,这个参数就是给线程函数传递的)

#include <iostream>
#include <pthread.h>
void* Test(void* args)
{
    std::cout << "hello pthread" << std::endl;
}
int mian()
{
    pthread_t td;
    pthread_create(&td,nullptr,Test,nullptr);
    return 0;   
}
用于等待指定线程的结束

int pthread_join(pthread_t thread,void** retval);
thread:要等待的线程的标识符。
retval:用于存储被等待线程的返回值。如果不关心返回值,可以传递 NULL。
如果成功,返回 0。
如果出错,返回错误码。

#include <iostream>
#include <pthread.h>
void* Test(void* args)
{
    std::cout << "hello pthread" << std::endl;
}
int mian()
{
    pthread_t td;
    pthread_create(&td,nullptr,Test,nullptr);

    pthread_join(td,nullptr); //不join线程,主线程退出,线程也会退出
    return 0;   
}
终止调用线程,并返回一个指定的值

void pthread_exit(void* retval);

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

void* thread_func(void* arg) {
    int thread_id = *(int*)arg;
    printf("Thread %d is running.\n", thread_id);

    // 终止线程并返回一个值
    int result = thread_id * 10;
    pthread_exit((void*)&result);
}

int main() {
    pthread_t thread;
    int thread_id = 123;

    // 创建线程
    pthread_create(&thread, NULL, thread_func, (void*)&thread_id);

    // 等待线程结束并获取返回值
    void* thread_result;
    pthread_join(thread, &thread_result);

    int* result_ptr = (int*)thread_result;
    printf("Thread result: %d\n", *result_ptr);

    return 0;
}
获取当前线程的线程 ID

pthread_t pthread_self(void);

请求取消指定线程

int pthread_cancel(pthread_t thread);
pthread_cancel函数用于向指定的线程发送取消请求。当调用该函数后,目标线程将收到一个取消请求,并根据其设置的取消状态进行响应。
返回值为0表示成功发送取消请求,非0值表示失败。

#include <iostream>
#include <pthread.h>
void* Test(void* args)
{
    while(true)
    {
        std::cout << "hello pthread" << std::endl;
        pthread_cancel(pthread_self());
    }
}
int mian()
{
    pthread_t td;
    pthread_create(&td,nullptr,Test,nullptr);

    pthread_join(td,nullptr); //不join线程,主线程退出,线程也会退出
    return 0;   
}
CLONE

clone 系统调用是 Linux 提供的一个用于创建新进程的系统调用
int clone(int (*fn)(void *), void child_stack, int flags, void arg, …);
fn:一个函数指针,指向新进程或线程的入口函数。
child_stack:子进程或线程的栈顶指针。对于进程,它指向新进程的用户栈顶;对于线程,它指向新线程的栈顶。栈通常需要提前分配并 映射到合适的内存区域。
flags:创建进程或线程的标志参数。
arg:传递给新进程或线程入口函数的参数。
…:可变参数列表,用于传递其他参数给入口函数。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>

int thread_func(void* arg) {
    int thread_id = *(int*)arg;
    printf("Thread %d is running.\n", thread_id);

    // 模拟线程执行
    for (int i = 0; i < 5; i++) {
        printf("Thread %d: %d\n", thread_id, i);
        sleep(1);
    }

    printf("Thread %d is finished.\n", thread_id);

    return 0;
}

int main() {
    int thread_id = 123;
    void* child_stack = malloc(16384); // 分配子线程栈空间,大小为16KB

    // 使用clone创建新线程
    int clone_flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD;
    int thread = clone(thread_func, (char*)child_stack + 16384, clone_flags, &thread_id);

    if (thread == -1) {
        perror("Failed to create thread");
        return 1;
    }

    printf("Main thread is running.\n");

    // 等待一段时间
    sleep(3);

    // 终止子线程
    if (kill(thread, SIGKILL) == -1) {
        perror("Failed to kill thread");
        return 1;
    }

    // 等待子线程结束
    if (waitpid(thread, NULL, 0) == -1) {
        perror("Failed to wait for thread");
        return 1;
    }

    printf("Main thread is finished.\n");

    free(child_stack);

    return 0;
}
线程分离

int pthread_detach(pthread_t thread);
成功返回 0;失败时,返回一个非零的错误码
用于将指定的线程标记为可被分离的。分离一个线程意味着当线程退出时,其资源(如线程的存 储空间)会被自动释放,而不需要其他线程调

#include <iostream>
#include <pthread.h>
void* Test(void* args)
{    
    pthread_detach(pthread_self());
    while(true)
    {
        std::cout << "hello pthread" << std::endl;
    }
}
int mian()
{
    pthread_t td;
    pthread_create(&td,nullptr,Test,nullptr);
    return 0;   
}
线程ID及进程地址空间布局

pthread_ create函数会产生一个线程ID,存放在第一个参数指向的地址中。该线程ID和前面说的线程ID
不是一回事。
前面讲的线程ID属于进程调度的范畴。因为线程是轻量级进程,是操作系统调度器的最小单位,所以需要
一个数值来唯一表示该线程。
pthread_ create函数第一个参数指向一个虚拟内存单元,该内存单元的地址即为新创建线程的线程ID,
属于NPTL线程库的范畴。线程库的后续操作,就是根据该线程ID来操作线程的。
在这里插入图片描述

<think>好的,用户想了解Linux线程的基本概念,我需要结合提供的引用资料来组织回答。首先,根据引用12,Linux并没有真正的线程数据结构,而是用进程模拟,但引用3提到线程由pthread库管理,这需要解释清楚。用户可能对“进程模拟线程”感到困惑,需要区分内核用户层的实现。 接下来,要说明Linux线程的本质是轻量级进程(LWP),引用34提到线程的控制管理由pthread库处理,而内核只看到LWP。这需要强调用户态内核态的分工,以及为什么线程切换成本较低。 然后,根据引用45,主线程退出会导致进程结束,即使分离线程还在运行。需要解释线程同步的重要性,比如pthread_join的使用,以及如何创建多个线程。这部分要提供代码示例,如引用5中的循环创建线程,但要注意用户可能对代码细节感兴趣,所以适当简化例子。 还要提到线程资源共享的特点,如地址空间、文件描述符等,与进程对比突出优势。同时,线程私有数据如栈寄存器需要说明,避免用户混淆线程进程的资源分配。 最后,相关问题要覆盖基本概念、管理方法、与进程的区别、同步机制实际应用,帮助用户扩展知识。需要确保引用正确,比如引用4关于主线程退出的影响,引用5的创建等待方法。 总结结构:分点阐述本质、管理、资源共享、同步机制,结合引用内容,保持语言简洁,避免技术术语过多,方便用户理解。检查LaTeX格式是否正确,尤其是数学公式代码块,确保符合用户的要求。</think>### Linux线程基本概念介绍 #### 1. 线程的本质 在Linux系统中,**线程本质是通过轻量级进程(LWP, Light Weight Process)实现的**,内核仅提供进程级别的调度单位,没有原生的“线程”数据结构[^1][^2]。线程共享同一进程的资源(如地址空间、文件描述符),但每个线程拥有独立的栈、寄存器线程本地存储(TLS)。 #### 2. 线程的管理 Linux线程的管理依赖**原生线程库(pthread)**。该库位于用户态,负责线程创建、销毁调度,而内核仅处理轻量级进程的调度[^3]。例如,通过以下代码可创建多个线程: ```c pthread_t tid[5]; for (int i = 0; i < 5; i++) { pthread_create(&tid[i], NULL, thread_func, NULL); } ``` #### 3. 线程与进程的关系 - **资源共享**:线程共享进程的全局变量、堆内存、文件描述符。 - **独立资源**:每个线程有独立的栈空间、程序计数器(PC)寄存器状态。 - **调度成本**:线程切换成本低于进程,因为无需切换地址空间。 #### 4. 线程同步与生命周期 - **主线程退出问题**:若主线程退出,整个进程会终止,所有线程(包括分离线程)将被强制结束[^4]。 - **同步方法**:需通过`pthread_join`等待线程结束,或使用互斥锁(mutex)协调资源访问: ```c pthread_join(tid[i], NULL); // 等待指定线程结束 ``` #### 5. 线程类型 - **可连接线程(Joinable)**:默认类型,需显式调用`pthread_join`回收资源。 - **分离线程(Detached)**:通过`pthread_detach`设置,结束后自动释放资源。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值