[Linux]线程概念和创建

线程概念:

线程:是进程内的一个执行分支。线程的执行颗粒度,比进程要细。
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来操作线程的。
在这里插入图片描述

  • 29
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值