Liunx:线程控制

目录

创建线程:pthread_create();

线程等待:pthread_join();

线程退出:pthread_exit();

线程取消:pthread_cancel()


说线程的时候说过,liunx没有选择单独定义线程的数据结构和适配算法,而是用轻量级进程来实现线程,有人将轻量级进程的系统调用进行了封装,在应用层实现了线程的相关功能,目前大部分的liunx平台都默认安装了第三方库,pthread.h。

创建线程:pthread_create();

man 一下该函数可以出现相关介绍:

pthread_t *thread,输出型参数,一个进程可以创建多个线程,为了方便控制,该参数返回线程的id。这个是你在该函数之前需要定义的一个变量,pthread_t是一个长整型。

const pthread_attr_t *attr,用来设置创建线程时的属性,一般我们传递一个空指针,线程的属性使用系统默认的就可以。

void *(*start_routine) (void *),函数指针,该函数返回值是void*,参数是void*。我们暂时把它叫做功能函数。

void *arg,第三个参数传递了一个函数,这个参数将来会传给你的功能函数做参数。

线程创建成功返回0,线程创建失败以返回值的形式返回错误码。

cpp 复制代码
#include <iostream>
#include <pthread.h>
#include <unistd.h>

using namespace std;

void *Function(void *arg)
{
    while (true)
    {
        cout << "new thread: " << getpid() << endl
             << endl;

        sleep(2);
    }
}

int main()
{

    pthread_t pid = 0;
    int err = pthread_create(&pid, nullptr, Function, nullptr);
    if (err == 0)
    {
        cout << " create thread successfully!  " << endl;
    }

    while (true)
    {

        cout << "main thread: " << getpid() << endl
             << endl;

        sleep(1);
    }

    return 0;
}

上面的代码演示了怎么创建一个线程,运行:


ldd 可以查看你的程序链接了哪些库:

查看进程也能看到只有一个mythread:

从这也能说明,一个进程可以有多个线程,多个线程只是一个进程不同的执行流。

但是查看线程的话,你可以明显看到这两个执行流:

LWP,light weight process id,轻量级进程id。PID=LWP的线程就是主线程,也就是程序运行最先创建的PCB。

当你任意的干掉一个线程,整个进程也会被干掉:

我们kill 的不是主线程,而是进程中的一个新线程,进程中的任意一个线程崩溃都会导致整个进程的崩溃。专业点说,多线程较单线程,程序的健壮性降低。

还要说一下创建线程成功后的第一个参数的值,用%p格式打印::

tid不等于LWP,实际上是一个地址,至于为什么,稍后说。


线程等待:pthread_join();

要等待某个线程,第一个参数就是创建该线程时的tid,第二个参数是用来取出你传入的功能函数的返回值。

等待成功返回0,失败返回错误码。

cpp 复制代码
void *Function(void *arg)
{
    int cnt=5;
    while (cnt--)
    {
        cout << "new thread: " << getpid() << endl
             << endl;

        sleep(1);
    }
}

int main()
{

    pthread_t pid = 0;
    int err = pthread_create(&pid, nullptr, Function, nullptr);
    if (err == 0)
    {
        cout << " create thread successfully!  " << endl;
    }

    int err_join=pthread_join(pid,nullptr);
    if(err_join==0)
    {
        cout<<" new thread wait successfully! main thread exit....."<<endl;
    }

    return 0;
}

运行:

主线程在等待新线程5秒运行完成后才退出,默认是阻塞等待。如果主线程比新线程先退出,会造成类似于僵尸进程的情况,也就是新线程的创建的一些资源无法回收,造成内存泄露的问题。

然后再说第二个参数。我们要知道一个函数的执行情况是根据函数的返回值,假如说我们没法在应用层接收功能函数的返回值,请问你如何知道函数的执行情况?或者你说可以通过错误码,但是一个进程只有一个错误码,可你有多个线程。其次我们无法捕捉到线程的异常,线程异常后整个进程都退出了,程序崩溃之后你只能知道有异常,至于哪个线程抛出的,没有办法捕捉。还有就是我们不主要用这个参数来查看线程的执行情况,他还有其他用途,后面说。在说为什么是一个二级指针。

我们的功能函数返回一个void*值,这个值在应用层,我们就假设功能函数执行完成的返回值返回到了pthread_join()函数里,你想要拿到一个函数内部的void*类型的值,那你的输出型参数就应该是void** retval,在函数内部进行复制*retval(void*)=void* ;这样类型就匹配了。这样用:

线程退出:pthread_exit();

线程退出你直接可以用return,也可以用这个,哪个线程调用这个函数,哪个线程就退出。

线程取消:pthread_cancel()

在主线程里不等新线程运行结束就直接取消。

cpp 复制代码
int main()
{

    pthread_t tid = 0;
    int err = pthread_create(&pid, nullptr, Function, nullptr);
    if (err == 0)
    {
        cout << " create thread successfully!  " << endl;
    }
    sleep(1);//等待一秒确保线程创建成功
    pthread_cancel(tid);
    void* retval=nullptr;

    pthread_join(tid,&retval);
    cout<<" new thread wait successfully! "<<"exit:"<<(long long int)retval<<"main thread exit....."<<endl;   
    return 0;
}

​
相关推荐
韦禾水1 天前
记录一次项目部署到tomcat的异常
java·tomcat
曦月合一1 天前
树莓派安装jdk、tomcat、vnc、谷歌浏览器开机自启等环境配置
java·tomcat·树莓派
harder3211 天前
RMP模式的创新突破
开发语言·学习·ios·swift·策略模式
jinanwuhuaguo1 天前
OpenClaw工程解剖——RAG、向量织构与“记忆宫殿”的索引拓扑学(第十三篇)
android·开发语言·人工智能·kotlin·拓扑学·openclaw
Rust研习社1 天前
使用 Axum 构建高性能异步 Web 服务
开发语言·前端·网络·后端·http·rust
此剑之势丶愈斩愈烈1 天前
openssl 自建证书
java
面汤放盐1 天前
何时使用以及何时不应使用微服务:没有银弹
java·运维·云计算
0xDevNull1 天前
Spring Boot 自动装配:从原理到实践
java·spring boot·后端
qq_589568101 天前
java学习笔记,包括idea快捷键
java·ide·intellij-idea
淘矿人1 天前
从0到1:用Claude启动你的第一个项目
开发语言·人工智能·git·python·github·php·pygame