Linux——线程概念&控制&创建&等待

目录

线程

概念图

提示

线程的控制

线程的创建

线程的终止

函数1

函数2

线程等待

线程分离


只有认知的突破 💫才能带来真正的成长 💫编程技术的学习 💫没有捷径 💫一起加油💫

🍁感谢各位的观看 🍁欢迎大家留言 🍁咱们一起加油 🍁努力成为更好的自己🍁

线程

概念:进程中的某个分开的执行流。

总结:在Linux系统中,没有线程这一说法。只有轻量级进程。

概念图

至于进程和线程的关系,如下图所示。

提示

  • 进程是系统资源划分的最小单位,线程是进程资源划分的最小单位。

如下所示的代码。

cpp 复制代码
#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>
void* fun(void*mesg)
{
    std::string messge=(const char*)(mesg);   //转化为string字符
    int i=10;
    while(i)
    {
        std::cout<<messge<<std::endl;
        sleep(1);
        i--;
    }
}
int main()
{
    pthread_t pwd;
    std::string ptr="我是一个线程";
    //创建线程,并分开执行流
    pthread_create(&pwd,nullptr,&fun,(void*)ptr.c_str());
    int i=20;
    //主线程执行
    while(i)
    {
        std::cout<<"我是进程"<<std::endl;
        sleep(1);
        i--;
    }
    return 0;
}

现象:代码的执行流被分流了,分为主执行流和分支流。

线程的控制

线程的创建

函数:int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine)(void*), void *arg)

参数:

  • thread:返回线程ID。

  • attr:设置线程的属性,attr为NULL表示使用默认属性。一般直接设为NULL。

  • start_routine:是个函数地址,线程启动后要执行的函数。

  • arg:传给线程启动函数的参数。这个参数会传给start_routine函数。

如下所示的代码。

cpp 复制代码
void* fun(void*mesg)
{
    std::string messge=(const char*)(mesg);   //转化为string字符
    int i=10;
    while(i)
    {
        std::cout<<messge<<std::endl;
        sleep(1);
        i--;
    }
}
 ****************************************************************   
pthread_t pwd;
std::string ptr="我是一个线程";
 //创建线程,并分开执行流
pthread_create(&pwd,nullptr,&fun,(void*)ptr.c_str());

thread参数

它返回的是在pthread库中,为进程创建的一个结构体对象的地址,类似于之前的FILE*指针。而这个结构体里面保存着线程所处的进程pid,自己的pid和自己的资源。

提示:对于线程库为这个线程创建的结构体对象,我们称为tcb。

如下所示的结构体。

cpp 复制代码
线程的tcb
struct pthread 
{
    /* Thread ID - which is also a 'is this thread descriptor (and 
    therefore stack) used' flag. */ 
    pid_t tid; //线程的
    /* Process ID - thread group ID in kernel speak. */ 
    pid_t pid; //所处进程的
}

查询线程的 指令

指令:ps -aL

cpp 复制代码
$ ps -aL | head -1 && ps -aL | grep mythread 
PID LWP TTY TIME CMD 
2711838 2711838 pts/235 00:00:00 mythread 
2711838 2711839 pts/235 00:00:00 mythread 

-L 选项:打印线程信息

线程的终止

函数1

函数:void pthread_exit(void *value_ptr)。哪个线程调用,就终止哪个线程。

参数

  • void *value_ptr:相当于exit(退出码),退出码。它所指向的变量必须是在堆上开辟的空间或者全局变量,千万不可是局部变量。

**注意:**线程的退出千万不可以用exit(),否则所有的线程和进程都会退出。

如下所示的代码。

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

int p=10;    //或全局变量
void* fun(void*mesg)
{
    std::string messge=(const char*)(mesg);   //转化为string字符
    int i=4;
    while(i)
    {
        std::cout<<messge<<std::endl;
        sleep(1);
        i--;
    }
    //或堆上开辟的空间
    // int*p=new int(10);
    // *p=10;
    pthread_exit((void*)&p);
}
int main()
{
    pthread_t pwd1;
    std::string ptr1="我是一个线程1";
    //创建线程,并分开执行流
    pthread_create(&pwd1,nullptr,&fun,(void*)ptr1.c_str());
    void*ret;
    pthread_join(pwd1,&ret);
    std::cout<<"获得退出信息"<<*(int*)(ret)<<std::endl;
    return 0;
}
函数2

函数:int pthread_cancel(pthread_t thread)。用来终止指定的线程。

如下所示的代码。

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

void* fun(void*mesg)
{
    std::string messge=(const char*)(mesg);   //转化为string字符
    int i=4;
    while(i)
    {
        std::cout<<messge<<std::endl;
        sleep(1);
        i--;
    }
}
int main()
{
    pthread_t pwd1;
    std::string ptr1="我是一个线程1";
    //创建线程,并分开执行流
    pthread_create(&pwd1,nullptr,&fun,(void*)ptr1.c_str());
    sleep(2);
    pthread_cancel(pwd1);   //取消指定的线程
    void*ret;
    pthread_join(pwd1,&ret);
    std::cout<<"获得退出信息"<<*(int*)(ret)<<std::endl;
    return 0;
}

线程等待

函数:int pthread_join(pthread_t thread, void **value_ptr),等待指定的线程。

它会阻塞的等待。

为什么需要线程等待?

  • 已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。

  • 创建新的线程不会复用刚才退出线程的地址空间。

线程分离

提示:如果不关心线程的返回值,join是⼀种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。

函数:int pthread_detach(pthread_t thread),分离指定线程。

函数:pthread_t pthread_self(void),线程获取自己的ID。

如下所示的代码。

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void *thread_run(void *arg)

{
    pthread_detach(pthread_self());
    printf("%s\n", (char *)arg);
    return NULL;
}
int main(void)
{
    pthread_t tid;
    if (pthread_create(&tid, NULL, thread_run, (void*)"thread1 run...") != 0)
    {
        printf("create thread error\n");
        return 1;
    }
    int ret = 0;
    sleep(1); // 很重要,要让线程先分离,再等待
    if (pthread_join(tid, NULL) == 0)
    {
        printf("pthread wait success\n");
        ret = 0;
    }
    else
    {    //因为线程分离了,所以无需等待,自然就会等待失败。
        printf("pthread wait failed\n");
        ret = 1;
    }
    return ret;
}
相关推荐
PPPPPaPeR.1 小时前
深入理解 Linux 文件系统:元数据、inode 与 block 核心原理
linux·运维·服务器
czxyvX2 小时前
006-Linux第一个小程序-进度条-初步理解缓冲区
linux
袁袁袁袁满2 小时前
Linux防火墙UFW和宝塔显示不同步问题如何解决?
linux·运维·服务器·宝塔·防火墙ufw
AI浩2 小时前
自动清理过期日志与媒体文件:防止服务器磁盘爆满的实用方案(find方案)
运维·服务器
野犬寒鸦2 小时前
CompletableFuture 在 项目实战 中 创建异步任务 的核心优势及使用场景
java·服务器·后端·性能优化
悲伤小伞2 小时前
Linux_传输层协议Udp
linux·网络协议·udp
程序员敲代码吗2 小时前
虚拟机内部工作机制揭秘:深入解析栈帧
java·linux·jvm
REDcker2 小时前
FFmpeg完整文档
linux·服务器·c++·ffmpeg·音视频·c·后端开发