【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局

这篇具有很好参考价值的文章主要介绍了【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

OS提供的轻量级进程接口

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
(关于 用户 → 库 → OS :具体可看下面线程地址空间布局)

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器

这个clone我们不用,这是OS提供给第三方库所用的接口

POSIX线程库

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

创建线程:
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
函数原型:

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

参数

  • thread:返回线程ID
  • attr:设置线程的属性,attr为NULL表示使用默认属性
  • start_routine:是个函数地址,线程启动后要执行的函数
  • arg:传给线程启动函数的参数

返回值:成功返回0;失败返回错误码

错误检查:

  • 传统的一些函数是,成功返回0,失败返回-1,并且对全局变量errno赋值以指示错误。
  • pthreads函数出错时不会设置全局变量errno(而大部分其他POSIX函数会这样做)。而是将错误代码通过返回值返回
  • pthreads同样也提供了线程内的errno变量,以支持其它使用errno的代码。对于pthreads函数的错误,
    建议通过返回值业判定,因为读取返回值要比读取线程内的errno变量的开销更小

线程使用

1.如何创建一堆线程

试验:创建一批线程:

#include <iostream>
#include <string>
#include <vector>
#include <pthread.h>
#include <unistd.h>

using namespace std;
void *start_routine(void *args)
{
    string name = static_cast<const char *>(args);
    while (true)
    {
        cout << "new thread create success , name: " << name << endl;
        sleep(1);
    }
}
int main()
{
    vector<pthread_t> tids;
#define NUM 10
    for (int i = 0; i < NUM; i++)
    {
        pthread_t tid;
        char namebuffer[64];
        snprintf(namebuffer, sizeof(namebuffer), "%s:%d", "thread", i);
        pthread_create(&tid, nullptr, start_routine, namebuffer);
        // sleep(1);
    }
    while (true)
    {
        cout << "new thread create success , name: main thread" << endl;
        sleep(1);
    }
    return 0;
}

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器

为什么这里连续输出9呢?
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器

我们这样的写法是有问题的,我们可以对其进行更改:

class ThreadData
{
public:
    int number;
    pthread_t tid;
    char namebuffer[64];
};
void *start_routine(void *args)
{
    ThreadData *td = static_cast<ThreadData *>(args); // 安全的进行强制类型转化
    int cnt = 10;
    while (cnt)
    {
        cout << "new thread create success, name: " << td->namebuffer << " cnt: " << cnt-- << endl;
    }
    delete td;
    return nullptr;
}
int main()
{
    vector<ThreadData *> threads;
#define NUM 10
    for (int i = 0; i < NUM; i++)
    {
        ThreadData *td = new ThreadData();
        td->number = i + 1;
        snprintf(td->namebuffer, sizeof(td->namebuffer), "%s:%d", "thread", i + 1);
        pthread_create(&td->tid, nullptr, start_routine, td);
        threads.push_back(td);
    }
    for (auto &iter : threads)
    {
        cout << "create thread: " << iter->namebuffer << " : " << iter->tid << " suceesss" << endl;
    }
    while (true)
    {
        cout << "new thread create success , name: main thread" << endl;
        sleep(1);
    }
    return 0;
}

将其创建成结构体,每次创建都new一个ThreadData对象,然后将结构体对象的地址传递给start_routine,每一个结构体对象都有自己独立的缓冲区,这样就能避免缓冲区被刷新了的问题。
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器

思考:start_routine这个函数被10个线程同时运行,它是什么状态?函数里面定义的tdcnt在变化会影响别的线程吗?
start_routine这个函数现在是重入状态,该函数是可重入函数,虽然cnt在变化,但是在函数内定义的变量,都叫做局部变量,具有临时性,现在依旧适用在多线程情况下,也没有问题。其实每一个线程都有自己独立的栈结构!(打印输出现在不解释,这个输出是往文件输出,当然只能执行一个)

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器

2.线程如何终止

  1. return nullptr;线程函数结束,return的时候,线程就算终止了
  2. pthread_exit(nullptr);我们在start_routine函数while循环中终止:
void *start_routine(void *args)
{
    sleep(1);
    ThreadData *td = static_cast<ThreadData *>(args); // 安全的进行强制类型转化
    int cnt = 10;
    while (cnt)
    {
        cout << "cnt : " << cnt << " &cnt: " << &cnt << endl;
        cnt--;
        pthread_exit(nullptr);//终止线程
        sleep(1);
    }
    delete td;
    return nullptr;
}

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
循环打印线程脚本:

while :; do ps -aL | head -1 && ps -aL | grep mythread;sleep 1;done

我们不能之间在线程中使用exit(),因为这是直接终止进程的,如果有线程调用这个函数,那么整个线程都会终止,pthread_exit(nullptr);可以终止新线程而不影响主线程。

3.线程如何取消

线程是可以被取消的但是注意:线程要被取消,前提是这个线程已经跑起来了
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
函数原型:

int pthread_cancel(pthread_t thread);

实操代码:

//新线程部分代码
void* start_routine(void *args)
{
	//....
    return (void*)123;
}
//主线程部分代码
for(int i = 0; i < threads.size()/2; i++)
{
    pthread_cancel(threads[i]->tid);
    cout << "pthread_cancel : " << threads[i]->namebuffer << " success" << endl;
}
for (auto &iter : threads)
{
    void* tmp=nullptr;
    int n = pthread_join(iter->tid, &tmp);
    assert(n == 0);
    cout << "join thread : " << iter->namebuffer <<"exit : "<< (long long)tmp << endl;
    delete iter;
}

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
线程如果是被取消的,退出码:-1(PTHREAD_CANCELED)


线程等待

线程也是要被等待的,如果不等待,会造成类似僵尸进程的问题–内存泄漏

线程必须也要被等待:

  1. 获取新线程的退出信息→可以不关心退出信息吗?可以
  2. 回收新线程对应的PCB等内核资源,防止内存泄漏 – 暂时无法查看!

线程等待函数pthread_join:
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
函数原型:

int pthread_join(pthread_t thread, void **retval);

在主线程中等待并释放:

for (auto &iter : threads)
{
    int n = pthread_join(iter->tid,nullptr);
    assert(n ==0);
    cout << "join thread : " << iter->namebuffer << " success" << endl;
    delete iter;
}

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器


线程退出返回值

我们的start_routine函数返回值是void*类型,这个类型有什么说法吗?
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器

//新线程部分代码
void *start_routine(void *args)
{
    //....
    return (void*)123;
}
//主线程部分代码:
for (auto &iter : threads)
{
    void* tmp=nullptr;
    int n = pthread_join(iter->tid, &tmp);
    assert(n == 0);
    cout << "join thread : " << iter->namebuffer <<"exit : " << (long long)tmp<< " success" << endl;//(long long)类型是因为我使用的Linux版本是64位的
    delete iter;
}
//其余代码跟之前一样,这里只是增加的或更改了一点

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器

这个的返回值也跟上述return是一样的

pthread_exit((void*)123);

既然假的地址,整数都能被外部拿到,那么如何返回的是,堆空间的地址呢?对象的地址呢?
返回一个对象指针:

class ThreadReturn
{
public:
    int exit_code;
    int exit_result;
};
//新线程部分代码
void* start_routine(void *args)
{
	//.....
    ThreadReturn * tr = new ThreadReturn();
    tr->exit_code = 1;
    tr->exit_result = 123;
    return (void*)tr;
}
//主线程部分代码
for (auto &iter : threads)
{
    ThreadReturn* tmp=nullptr;
    int n = pthread_join(iter->tid, (void**)&tmp);
    assert(n == 0);
    cout << "join thread : " << iter->namebuffer <<"exit_code : " << tmp->exit_code<< " exit_result : "<<tmp->exit_result << endl;
    delete iter;
}

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器

为什么没有见到,线程退出的时候,对应的退出信号???
线程出异常,收到信号,整个进程都会退出!pthread_join:默认就认为函数会调用成功!不考虑异常问题,异常问题是进程该考虑的问题!


C++11的多线程

#include <iostream>
#include <unistd.h>
#include <thread>

void thread_run()
{
    while (true)
    {
        std::cout << "我是新线程..." << std::endl;
        sleep(1);
    }
}

int main()
{
    std::thread t1(thread_run);

    while (true)
    {
        std::cout << "我是主线程..." << std::endl;
        sleep(1);
    }

    t1.join();

    return 0;
}

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
任何语言,在linux中如果要实现多线程,必定要是用pthread库

如何看待C++11中的多线程呢?
C++11 的多线程,在Linux环境中,本质是对pthread库的封装!(使用原生线程库还是C++11的线程库都可以,只是C++11的线程库在windows下也能运行,Linux与windows底层的线程库的接口不一样)


线程ID及地址空间布局

  • pthread_create函数会产生一个线程ID,存放在第一个参数指向的地址中。该线程ID和前面说的线程ID不是一回事。
  • 前面讲的线程ID属于进程调度的范畴。因为线程是轻量级进程,是操作系统调度器的最小单位,所以需要一个数值来唯一表示该线程。
  • pthread_create函数第一个参数指向一个虚拟内存单元,该内存单元的地址即为新创建线程的线程ID,属于NPTL线程库的范畴。线程库的后续操作,就是根据该线程ID来操作线程的。
  • 线程库NPTL提供了pthread_self函数,可以获得线程自身的ID

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器

#include <iostream>
#include <string>
#include <pthread.h>
#include <unistd.h>

std::string changeId(const pthread_t &thread_id)
{
    char tid[128];
    snprintf(tid, sizeof(tid), "0x%x", thread_id);
    return tid;
}

void *start_routine(void *args)
{
    std::string threadname = static_cast<const char *>(args);
    while (true)
    {
        std::cout << threadname << " running ... : " << changeId(pthread_self()) << std::endl;
        sleep(1);
    }

    return nullptr;
}
int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, start_routine, (void *)"thread 1");
    std::string main_id = changeId(pthread_self());
    std::cout << "main thread running ... new thread id: " << changeId(tid) <<" main thread id: " << main_id << std::endl;
    pthread_join(tid,nullptr);
    return 0;
}

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器

线程地址空间布局

pthread_t 到底是什么类型呢?取决于实现。对于Linux目前实现的NPTL实现而言,pthread_t类型的线程ID,本质就是一个进程地址空间上的一个地址。

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
原生线程库可能存在多个线程,我们同样也要对线程进行管理(先描述再组织),每一个轻量级进程对应原生库中的一个结构体对象(TCB),这是Linux的方案 – 用户级线程,用户关心的线程属性在库中,而内核里面提供执行流的调度。Linux用户级线程对比内核轻量级进程是1:1。

线程布局图:
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器

用户级线程:线程ID值就是库中结构体(TCB)对象的地址

线程局部存储

我们在之前的“什么是线程?”一文已经了解到了:线程一旦被创建,几乎所有资源都是被线程所共享的

//定义一个全局变量
int g_val= 100;
//新线程:
std::cout << threadname << " running ... : " << changeId(pthread_self()) 
		  <<" g_val: "<< g_val++ << " &g_val: " << &g_val << std::endl;
//主线程:
std::cout << "main thread running ... new thread id: " <<changeId(tid) 
          <<" main thread id: " << main_id << " g_val: "<< g_val << " &g_val: " << &g_val << std::endl;

我们在主线程与新线程都打印输出g_val的值与地址:
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
我们可以发现,主线程与新线程都是输出同一个g_val值与地址,且这个地址非常小

添加__thread,可以将一个内置类型设置为线程局部存储

__thread int g_val = 100;

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
我们可以发现,给g_val添加__thread后,主线程与新线程打印输出的地址不一样了,新线程对g_val的值进行修改,主线程打印的值没有变化。

原因图:
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
一开始g_val已初始化数据段,添加__thread以后,使其设置为线程局部存储,每个线程都有一份且是在共享区已初始化数据段→共享区(地址由低到高),且它们访问不会互相影响。


分离线程

  • 默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。
  • 如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。
  • 如果线程设置了分离状态,那么就不能join等待了。

分离一个线程:
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
函数原型:

int pthread_detach(pthread_t thread);

可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离

验证分离以后不能join(里面有小bug,请思考):

#include <iostream>
#include <string>
#include <pthread.h>
#include <cstring>
#include <unistd.h>
std::string changeId(const pthread_t &thread_id)
{
    char tid[128];
    snprintf(tid, sizeof(tid), "0x%x", thread_id);
    return tid;
}
void *start_routine(void *args)
{
    std::string threadname = static_cast<const char *>(args);
    // pthread_detach(pthread_self());
    int cnt = 5;
    while (cnt--)
    {
        std::cout << threadname << " running ... : " << changeId(pthread_self()) << std::endl;
        sleep(1);
    }
    return nullptr;
}
int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, start_routine, (void *)"thread 1");
    std::string main_id = changeId(pthread_self());
    std::cout << "main thread running ... new thread id: " << changeId(tid) <<" main thread id: " << main_id << std::endl;
    int n = pthread_join(tid,nullptr);
    std::cout << "result : " << n << " : " << strerror(n) <<std::endl;
    return 0;
}

1.我们在start_routine里面没有使用线程分离:
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
2.我们在start_routine里面使用线程分离pthread_detach
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
思考:为什么我在start_routine里面使用线程分离pthread_detach然后pthread_join还是成功了?
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
原因:由于主线程创建新线程以后,到底是主线程先运行还是新线程先运行是随机的,如果主线程先运行了pthread_join使得其已经阻塞式等待了,然后新线程才pthread_detach分离,这个时候已经晚了。
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器

当然这种分离方式我们不赞成,我们一般这样使用线程分离:

std::string changeId(const pthread_t &thread_id)
{
    char tid[128];
    snprintf(tid, sizeof(tid), "0x%x", thread_id);
    return tid;
}
void *start_routine(void *args)
{
    std::string threadname = static_cast<const char *>(args);
    int cnt = 5;
    while (cnt--)
    {
        std::cout << threadname << " running ... : " << changeId(pthread_self()) << std::endl;
        sleep(1);
    }
    return nullptr;
}
int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, start_routine, (void *)"thread 1");
    std::string main_id = changeId(pthread_self());
    pthread_detach(tid);//线程分离

    std::cout << "main thread running ... new thread id: " << changeId(tid) << " main thread id: " << main_id << std::endl;

    // int n = pthread_join(tid,nullptr);
    // std::cout << "result : " << n << " : " << strerror(n) <<std::endl;
    while (true)
    {
        std::cout << "main thread running ... " << std::endl;
    }
    return 0;
}

【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器
【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局,Linux基础,linux,线程控制,线程等待,线程分离,运维,服务器


如有错误或者不清楚的地方欢迎私信或者评论指出🚀🚀文章来源地址https://www.toymoban.com/news/detail-606661.html

到了这里,关于【Linux】详解线程控制 -- 线程用法 | 线程等待 | 线程ID及地址空间布局的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux-14】进程地址空间&虚拟空间&页表——原理&知识点详解

    前言 大家好吖,欢迎来到 YY 滴 系列 ,热烈欢迎! 本章主要内容面向接触过Linux的老铁 主要内容含: 欢迎订阅 YY 滴C++专栏!更多干货持续更新!以下是传送门! YY的《C++》专栏 YY的《C++11》专栏 YY的《Linux》专栏 YY的《数据结构》专栏 YY的《C语言基础》专栏 YY的《初学者易

    2024年04月29日
    浏览(51)
  • 『Linux』第九讲:Linux多线程详解(二)_ 线程控制

    「前言」文章是关于Linux多线程方面的知识,上一篇是 Linux多线程详解(一),今天这篇是 Linux多线程详解(二),讲解会比较细,下面开始! 「归属专栏」Linux系统编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 「枫叶先生有点文青病」「每篇一句」 纵有千古,横有八荒

    2024年02月01日
    浏览(46)
  • 多线程系列(六) -等待和通知模型详解

    在之前的线程系列文章中,我们介绍了 synchronized 和 volatile ,使用它能解决线程同步的问题,但是它们无法解决线程之间协调和通信的问题。 举个简单的例子,比如线程 A 负责将 int 型变量 i 值累加操作到 10000,然后通知线程 B 负责把结果打印出来。 这个怎么实现呢?

    2024年02月22日
    浏览(40)
  • Linux进程控制【创建、终止、等待】

    ✨个人主页: Yohifo 🎉所属专栏: Linux学习之旅 🎊每篇一句: 图片来源 🎃操作环境: CentOS 7.6 阿里云远程服务器 Good judgment comes from experience, and a lot of that comes from bad judgment. 好的判断力来自经验,其中很多来自糟糕的判断力。 进程 创建后,需要对其进行合理管理,光靠

    2024年02月02日
    浏览(65)
  • 【Linux】进程控制(创建、终止、等待)

    环境:centos7.6,腾讯云服务器 Linux文章都放在了专栏:【 Linux 】欢迎支持订阅 相关文章推荐: 【Linux】冯.诺依曼体系结构与操作系统 【Linux】进程理解与学习Ⅰ-进程概念 【Linux】进程理解与学习Ⅱ-进程状态 【Linux】进程理解与学习Ⅲ-环境变量 【Linux】进程理解与学习Ⅳ

    2023年04月16日
    浏览(59)
  • Linux - 进程控制(下篇)- 进程等待

     为什么进程需要等待?  我们知道,在Linux 当中, 父子进程之间一些结构 就是一些 多叉树 的结构,一个父进程可能管理或者创建了很多个字进程。 而其实我们在代码当中使用fork()函数创建的子进程的父进程,这个父进程其实也是其他的父进程的子进程,我们在命令行

    2024年02月05日
    浏览(41)
  • 【linux进程控制(二)】进程等待--父进程是如何等待子进程死亡的?

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:Linux从入门到精通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学更多操作系统知识   🔝🔝 ) 控制一个进程包括如何创建它,如何 终止它,并且如何回收它的资源! 本章重点: 本篇文章着重讲解进程等待的必要性 ,以及

    2024年02月05日
    浏览(37)
  • linux入门之进程控制(上)进程创建,进程等待

    目录 一、进程创建 1.fork函数 2.fork函数返回值 3.写时拷贝 4.fork常规用法 5.fork调用失败原因 二、进程终止 1.进程退出场景 2.进程常见退出方法 2.1_exit函数(直接调用内核) 2.2 exit函数 2.3return退出 三、进程等待 1.进程等待必要性 2.进程等待方法 2.1 wait方法 2.2 waitpid方法 2.3获取

    2024年02月12日
    浏览(56)
  • 【当前全网最详细】WebUI中使用Instant_ID来控制生成对象面部的用法

    中文网络上或者B站很多UP,在讲述WebUI中使用这个controlnet来换脸的时候,要么讲的过于复杂,要么就是没有讲清楚,所以这里整理下详细的使用方法,并记录下生成的内容。  如果懒得看文字可以看同款视频哈: 【AI写真Instant_ID全网最详细教程Stable Diffusion WebUI免费生产力】

    2024年03月21日
    浏览(38)
  • 【Linux进程控制】进程创建 | 进程终止 | 进程等待 | 进程替换

    【写在前面】 本文主要学习理解 fork 的返回值、写时拷贝的工作细节、为什么要存在写时拷贝;进程退出码、进程退出的场景及常见的退出方法、对比 man 2 _exit 和 man 3 exit;进程终止、操作系统怎么进行释放资源、池的概念;进程等待的价值、进程等待的方法 wait 和 waitpid

    2023年04月08日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包