Linux之线程控制

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

目录

一、POSIX线程库

二、线程的创建

三、线程等待

四、线程终止

五、分离线程

六、线程ID:pthread_t

1、获取线程ID

2、pthread_t

七、线程局部存储:__thread


一、POSIX线程库

由于Linux下的线程并没有独立特有的结构,所以Linux并没有提供线程相关的接口。

而我们所说的,pthread线程库是应用层的原生线程库。这个线程库并不是系统接口直接提供的,而是由第三方帮我们提供的。

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

二、线程的创建

pthread_create:其功能就是创建线程。

NAME
       pthread_create - create a new thread

SYNOPSIS
       #include <pthread.h>

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

       Compile and link with -pthread.

参数说明:

thread:获取创建成功的线程ID,该参数是一个输出型参数。

attr:用于设置创建线程的属性,传入nullptr表示使用默认属性。(我们一般不关心,直接设为nullptr)

start_routine:该参数是一个函数指针,表示线程启动后要执行的函数。

arg:传给线程执行函数的参数。

返回值:线程创建成功返回0,失败返回错误码。返回值也可以自己设置,返回给主线程。主线程通过pthread_join获取。

主线程:当一个程序启动时,就有一个进程被操作系统创建,与此同时一个线程也立刻运行,这个线程就叫做主线程。

下面我们让主线程调用pthread_create函数创建一个新线程:

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

using namespace std;

void *thread_run(void *argc)
{
    cout << "new thread pid: " << getpid() << "\n"
         << endl;

    sleep(20);
    return nullptr;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, thread_run, (void *)"thread 1");

    while (true)
    {
        cout << "main thread pid: " << getpid() << endl;
        sleep(1);
    }

    return 0;
}

 Linux之线程控制,java,jvm,开发语言

使用ps -aL命令,可以显示当前的轻量级进程。

Linux之线程控制,java,jvm,开发语言

从上图,我们看到两个线程的PID相同,说明他们属于同一个进程。但是他们的LWP值不同,说明他们是两个不同的线程。LWP就是轻量级进程的ID。

注:在Linux中,线程与内核的LWP是一一对应的,实际上操作系统调度的时候是根据LWP调度的,而不是PID,只不过我们之前接触到的都是单线程进程,其PID和LWP是相等的,所以对于单线程进程来说,调度时采用PID和LWP是一样的。

我们也可以让一个主线程创建多个新线程

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

using namespace std;

void *thread_run(void *argc)
{
    string name = (char *)argc;
    while (true)
    {
        cout << name << "---"
             << "pid: " << getpid() << "\n"
             << endl;
        sleep(1);
    }
}

int main()
{
    pthread_t tid[5];
    char name[64];
    for (int i = 0; i < 5; i++)
    {
        snprintf(name, sizeof(name), "%s-%d", "thread", i);
        pthread_create(tid + i, nullptr, thread_run, (void *)name);
        sleep(1);
    }

    while (true)
    {
        cout << "main thread pid: " << getpid() << endl;
        sleep(3);
    }

    return 0;
}

Linux之线程控制,java,jvm,开发语言

因为主线程和五个新线程都属于同一个进程,所以它们的PID都是一样的。 

三、线程等待

一个线程被创建出来,那么这个线程就如同进程一般,也是需要被等待的。如果主线程不对新线程进行等待,那么这个新线程的资源也是不会被回收的。如果不等待会产生类似于“僵尸进程”的问题,也就会造成内存泄漏。所以线程需要被等待。

pthread_join:其功能就是进行线程等待

NAME
       pthread_join - join with a terminated thread

SYNOPSIS
       #include <pthread.h>

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

       Compile and link with -pthread.

参数说明:

thread:被等待线程的ID。
retval:线程退出时的退出码信息。

返回值:线程等待成功返回0,失败返回错误码。

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

using namespace std;

void *thread_run(void *argc)
{
    int count = 10;
    while (true)
    {
        sleep(1);
        if (count++ == 10)
            break;
    }

    cout << "new thread  done ... quit" << endl;
    return nullptr;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, thread_run, (void *)"thread1");
    pthread_join(tid, nullptr);
    cout << "main thread wait done ... quit" << endl;

    return 0;
}

Linux之线程控制,java,jvm,开发语言

第二个参数是用来获取新线程返回值的。主线程可以通过新线程的返回值拿到新线程的计算结果(该结果也可以保存在堆空间上)

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

using namespace std;

void *thread_run(void *argc)
{
    int count = 10;
    while (true)
    {
        sleep(1);
        if (count++ == 10)
            break;
    }

    cout << "new thread  done ... quit" << endl;
    return (void *)10;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, thread_run, (void *)"thread1");
    void *ret = nullptr;
    pthread_join(tid, &ret);
    cout << "main thread wait done ... quit"
         << " " << (long long)ret << endl;

    return 0;
}

Linux之线程控制,java,jvm,开发语言

四、线程终止

return:最简单的终止线程的方式,就是使用return返回一个返回值来终止线程。

pthread_exit:其功能就是终止一个线程。(终止线程不能使用exit,因为它是用来终止进程的)

参数,retval:设置退出结果。

NAME
       pthread_exit - terminate calling thread

SYNOPSIS
       #include <pthread.h>

       void pthread_exit(void *retval);

       Compile and link with -pthread.
#include <iostream>
#include <unistd.h>
#include <string>
#include <pthread.h>

using namespace std;

void *thread_run(void *argc)
{
    int count = 10;
    while (true)
    {
        sleep(1);
        if (count++ == 10)
            break;
    }

    cout << "new thread  done ... quit" << endl;
    pthread_exit((void*)17);
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, thread_run, (void *)"thread1");
    void *ret = nullptr;
    pthread_join(tid, &ret);
    cout << "main thread wait done ... quit"
         << " " << (long long)ret << endl;

    return 0;
}

 Linux之线程控制,java,jvm,开发语言

pthread_cancel:其功能是取消一个线程。

参数,thread:线程ID。

NAME
       pthread_cancel - send a cancellation request to a thread

SYNOPSIS
       #include <pthread.h>

       int pthread_cancel(pthread_t thread);

       Compile and link with -pthread.
#include <iostream>
#include <unistd.h>
#include <string>
#include <pthread.h>

using namespace std;

void *thread_run(void *argc)
{
    string name = (char *)argc;
    int count = 10;
    while (true)
    {
        sleep(1);
        if (count++ == 10)
            break;
    }

    cout << "new thread  done ... quit" << endl;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, thread_run, (void *)"thread1");
    void *ret = nullptr;
    pthread_cancel(tid);
    pthread_join(tid, &ret);
    cout << "main thread wait done ... quit"
         << " " << (long long)ret << endl;

    return 0;
}

 Linux之线程控制,java,jvm,开发语言

线程被取消,线程等待时获取的退出码为-1。 

五、分离线程

新线程退出后,主线程需要对其进行pthread_join操作,否则无法释放资源,从而造成内存泄漏。
但如果主线程不关心新线程的返回值,此时我们可以将该新线程进行分离,后续当新线程退出时就会自动释放线程资源。

一个线程如果被分离了,这个线程依旧要使用该进程的资源,依旧在该进程内运行,甚至这个线程崩溃了一定会影响其他线程,只不过这个线程退出时不再需要主线程去join了,当这个线程退出时系统会自动回收该线程所对应的资源。

pthread_detach:其功能就是进行分离线程。一般是线程自己分离。

int pthread_detach(pthread_t thread);

参数说明:thread:被分离线程的ID。

返回值说明:

线程分离成功返回0,失败返回错误码。

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

using namespace std;

void *thread_run(void *argc)
{
    pthread_detach(pthread_self());
    int count = 10;
    while (true)
    {
        sleep(1);
        if (count++ == 10)
            break;
    }

    cout << "new thread  done ... quit" << endl;
    pthread_exit((void*)17);
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, thread_run, (void *)"thread1");
    void *ret = nullptr;
    cout << "main thread wait done ... quit"
         << " " << (long long)ret << endl;

    return 0;
}

Linux之线程控制,java,jvm,开发语言

 如果我们在线程分离了之后,任然等待,会怎么样呢?

#include <iostream>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <pthread.h>

using namespace std;

void *thread_run(void *argc)
{
    pthread_detach(pthread_self());
    int count = 9;
    while (true)
    {
        sleep(1);
        if (count++ == 10)
            break;
    }

    cout << "new thread  done ... quit" << endl;
    pthread_exit((void *)17);
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, thread_run, (void *)"thread1");
    sleep(2);
    int n = pthread_join(tid, nullptr);
    cout << "n: " << n << "errstring: " << strerror(n) << endl;

    return 0;
}

Linux之线程控制,java,jvm,开发语言

六、线程ID:pthread_t

pthread_create函数会产生一个线程ID,存放在第一个参数指向的地址中,该线程ID和内核中的LWP是完全不一样的。内核中的LWP属于进程调度的范畴,需要一个数值来唯一表示该线程。

那么pthread_t到底是什么类型呢?

1、获取线程ID

pthread_self:获取线程的ID。

#include <iostream>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <pthread.h>

using namespace std;

void *thread_run(void *argc)
{
    int count = 9;
    while (true)
    {
        sleep(1);
        if (count++ == 10)
            break;
    }

    cout << "new thread  done ... quit"
         << "new thread ID: " << pthread_self() << endl;
    pthread_exit((void *)17);
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, thread_run, (void *)"thread1");
    void *ret = nullptr;
    sleep(2);
    cout << "main thread ID: " << pthread_self() << endl;
    pthread_join(tid, &ret);

    return 0;
}

Linux之线程控制,java,jvm,开发语言

为什么线程的ID数值这么大呢?下面我们就来讲一讲。 

2、pthread_t

进程运行时线程动态库被加载到内存,然后通过页表映射到进程地址空间中的共享区,此时该进程内的所有线程都是能看到这个动态库的。

Linux之线程控制,java,jvm,开发语言

其中主线程采用的栈是进程地址空间中原生的栈,而其余线程采用的栈就是由线程库帮我们在共享区中开辟的。

线程库给每个新线程提供属于自己的struct pthread,当中包含了对应线程的各种属性;每个线程还有自己的线程局部存储,当中包含了对应线程被切换时的上下文数据。其中,还有线程栈。如下图:

Linux之线程控制,java,jvm,开发语言

所以,线程ID本质就是进程地址空间共享区上对应的struct pthread的虚拟地址。 

七、线程局部存储:__thread

假设有一个全局变量:g_val。我们知道,各个线程是共享全局变量的。不同的线程可以对同一个全局变量进行操作。那么如果我们想让每个线程都拥有属于自己的g_val,那么我们可以加上关键字:__thread。这种现象就叫做线程局部存储。文章来源地址https://www.toymoban.com/news/detail-838563.html

到了这里,关于Linux之线程控制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【Linux】多线程1——线程概念与线程控制

    📝 个人主页 :超人不会飞) 📑 本文收录专栏 :《Linux》 💭 如果本文对您有帮助,不妨 点赞、收藏、关注 支持博主,我们一起进步,共同成长! 💭理解线程需要和进程的概念紧密联系。 线程是一个执行分支,执行粒度比进程更细,调度成本更低; 进程是分配系统资源的

    2024年02月12日
    浏览(29)
  • Linux 多线程( 进程VS线程 | 线程控制 )

    进程是资源分配的基本单位。 线程是OS调度的基本单位。 线程共享进程数据,但也拥有自己的一部分数据: 线程ID 一组寄存器 ,用来保存每个线程的上下文数据,让每个线程能够合理调度。 栈 ,每个线程入栈出栈产生的临时变量必须保存到每个线程的私有栈中,所以栈对于

    2024年02月07日
    浏览(44)
  • 【Linux学习】多线程——线程控制 | 线程TCB

    🐱作者:一只大喵咪1201 🐱专栏:《Linux学习》 🔥格言: 你只管努力,剩下的交给时间! Linux内核中并不存在线程的概念,我们程序员是通过库来使用线程的,这个库是POSIX线程库,是由原生线程库提供的,它遵守POSIX标准,就像之前学过的System V标准一样。POSIX线程库有以

    2024年02月05日
    浏览(31)
  • 【Linux】多线程 --- 线程概念 控制 封装

    从前种种,譬如昨日死。从后种种,往如今日生。 1.1 进程资源如何进行分配呢?(地址空间+页表) 1. 首先我们来看一个现象,当只有第一行代码时,编译是能通过的,但会报warning,当加了第二行代码时,编译无法通过,报error。 第一行代码能编过的原因是权限缩小,虽然

    2024年02月03日
    浏览(64)
  • 【Linux】多线程01 --- 理解线程 线程控制及封装

    🍎 作者: 阿润菜菜 📖 专栏: Linux系统编程 在Linux中其实没有真正线程的概念,在Linux中线程的概念其实就是进程内部的一个执行流。在宏观层面上理解,线程是执行流这句话放在任何一个OS上都没错,但落实到具体操作系统上,不同的OS多线程实现策略是不一样的,例如

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

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

    2024年02月01日
    浏览(46)
  • Linux--线程-条件控制实现线程的同步

    1.条件变量 条件变量是线程另一可用的同步机制。条件变量给多个线程提供了一个会合的场所。条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生。 条件本身是由互斥量保护的。线程在改变条件状态前必须首先锁住互斥量,其他线程在获得互斥量之

    2024年02月05日
    浏览(40)
  • 多线程基础入门【Linux之旅】——上篇【线程控制,线程互斥,线程安全】

    目录 前文 回望页表 一,什么是线程 二,使用 pthread_create (线程创建) 三,线程控制 1 ,线程共享进程数据,但也拥有自己的一部分数据: 2, 线程  VS 进程优点 3,pthread_join(等待线程) 4,pthread_exit (线程终止) 5, pthread_cancel (线程取消) 6. pthread_t 类型 7.  pthread_detac

    2024年01月16日
    浏览(55)
  • java语法(二)线程并发、Juit单元测试、反射机制、注解、动态代理、XML解析、JVM

    正则表达式验证网站 1、 ? :表示前边这个字符可以出现0次或者1次。例如下边 /used? 既可以匹配 use 也可以匹配 used 。 2、 * :匹配0个或者多个字符, * 号代表前边这个字符可以出现0次或者多次。例如 /ab*c 可以匹配 ac、abc、abbbbc 3、 + :与 * 号不同的是, + 需要前面这个字符

    2024年02月06日
    浏览(53)
  • Linux系统编程:线程控制

    目录 一. 线程的创建 1.1 pthread_create函数 1.2 线程id的本质 二. 多线程中的异常和程序替换 2.1 多线程程序异常 2.2 多线程中的程序替换 三. 线程等待 四. 线程的终止和分离 4.1 线程函数return 4.2 线程取消 pthread_cancel 4.3 线程退出 pthread_exit 4.4 线程分离 pthread_detach  五. 总结

    2024年02月11日
    浏览(44)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包