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;
}

​
相关推荐
echo17542515 分钟前
Apipost免费版、企业版和私有化部署详解
java
夜夜敲码21 分钟前
C语言教程(十六): C 语言字符串详解
c语言·开发语言
宋康28 分钟前
C语言结构体和union内存对齐
c语言·开发语言
异常君33 分钟前
Java 高并发编程:等值判断的隐患与如何精确控制线程状态
java·后端·代码规范
异常君33 分钟前
Java 日期处理:SimpleDateFormat 线程安全问题及解决方案
java·后端·代码规范
都叫我大帅哥35 分钟前
Spring AI中的ChatClient:从入门到精通,一篇搞定!
java·spring·ai编程
都叫我大帅哥36 分钟前
《@SpringBootApplication:Spring Boot的"一键启动"按钮,还是程序员的"免死金牌"?》
java·后端·spring
居然是阿宋38 分钟前
Kotlin高阶函数 vs Lambda表达式:关键区别与协作关系
android·开发语言·kotlin
triticale41 分钟前
P12167 [蓝桥杯 2025 省 C/Python A] 倒水
java·蓝桥杯
-曾牛1 小时前
Spring AI 快速入门:从环境搭建到核心组件集成
java·人工智能·spring·ai·大模型·spring ai·开发环境搭建