🔍前言:在Linux操作系统的广阔天地里,线程作为并发编程的基本单位,扮演着举足轻重的角色。它们如同操作系统的微观脉络,穿梭于各个任务之间,高效地协调着系统的运行。然而,要想驾驭好这些微观世界的精灵,对线程控制的深入理解是不可或缺的
我们深知,在多线程编程的复杂环境中,如何有效地管理线程,是确保程序稳定性和性能的关键所在。因此,本文将深入剖析Linux线程控制的核心概念,从线程的创建与终止我们将一一为您揭开它们的神秘面纱
我们力求做到理论与实践相结合。我们不仅会详细介绍线程控制的相关理论知识,还会通过丰富的实战案例,让您在动手实践中加深对线程控制技术的理解和掌握。我们相信,通过本文的学习,您将能够更加自信地面对多线程编程中的挑战,编写出更加高效、稳定的程序
让我们携手共进,共同探索Linux多线程编程的无限魅力吧!
线程是进程中的一个执行单元,或者说是进程内的一条执行路径、一个执行流。它是被系统独立调度和分派的基本单位,负责执行进程中的代码。每个线程都有自己独立的线程ID、程序计数器、寄存器集合以及栈空间,但它们共享同一个进程的地址空间和其他资源,如全局变量、静态变量、堆内存等
让不同PCB指向同一块地址空间,共享进程的资源,线程在进程的地址空间中运行,线程就是一种类似与进程的轻量级进程,但是线程是一个没有独立的地址空间的PCB结构,线程切换效率高
注意:线程是CPU调度的基本单位,进程是承担系统调用的基本实体
Cache:
Cache是位于CPU和主存储器(DRAM)之间的一块高速缓冲存储器,规模较小但速度非常快,通常由SRAM(静态存储器)组成。其主要功能是暂时存储CPU即将访问的数据,从而提高CPU数据输入输出的速率。当CPU需要访问数据时,会首先在Cache中查找,如果找到所需数据,则直接从Cache中读取,避免了访问速度较慢的主存,从而提高了系统的整体性能
线程切换效率高的原因:
线程的优点:
线程的缺点:
线程异常:
线程用途:
进程是资源分配的基本单位,线程是调度的基本单位,线程共享进程数据,但也拥有自己的一部分数据
进程的多个线程共享 同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到
除了上面,各线程还会共享进程的其他资源:
POSIX线程库定义了一套用于创建、操纵和管理线程的API。这些API允许程序员在Unix-like系统(如Linux、Solaris)上编写多线程程序
pthread_
”打头的<pthread.h>
-lpthread
”选项如何查看线程:
指令:
ps -aL
pthread_create:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *
(*start_routine)(void*), void *arg);
参数说明:
thread
:返回线程IDattr
:设置线程的属性,attr为NULL表示使用默认属性start_routine
:是个函数地址,线程启动后要执行的函数arg
:传递给线程函数的参数,可以是任何类型的数据,但需要通过类型转换与线程函数中的参数类型匹配,也可以传一个类返回值:成功返回0;失败返回错误码
代码示例:
#include <iostream>
#include <unistd.h>
#include <pthread.h>
void *ThreadRoutine(void *args)
{
string threadname = static_cast<const char*>(args);
while(1)
{
cout << "new thread" << ", thread name: " << threadname << endl;
sleep(1);
}
}
int main()
{
pthread_t tid;
ThreadData *td = new ThreadData("thread_1", (uint64_t)time(nullptr), Print);
pthread_create(&tid, nullptr, ThreadRountine, td);
while(1)
{
cout << "I am a main thread" << endl;
sleep(1);
}
return 0;
}
在多线程编程中,线程终止(Thread Termination)是指一个线程结束其执行过程,释放相关资源,并退出其生命周期。线程终止可以是由于线程正常完成其任务,也可以是由于某些异常情况或外部请求导致的提前结束
只终止某个线程而不终止整个进程:
pthread_ exit
终止自己pthread_ cancel
终止同一进程中的另一个线程pthread_exit:
代码示例:(运行5秒后退出)
void *ThreadRoutine(void *args)
{
string threadname = static_cast<const char*>(args);
int cnt = 5;
while(cnt--)
{
cout << "new thread -> name: " << threadname << endl;
sleep(1);
}
// return nullptr;
pthread_exit(nullptr);
}
pthread_cancel:
int pthread_cancel(pthread_t thread);
参数:
thread
:线程ID代码示例:
void *ThreadRoutine(void *args)
{
string threadname = static_cast<const char*>(args);
int cnt = 5;
while(cnt--)
{
cout << "new thread -> name: " << threadname << endl;
sleep(1);
}
cout << "other thread cancel done" << endl;
return nullptr;
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread_1");
sleep(5);
// pthread_detach(tid);
int n = pthread_cancel(tid);
cout << "main thread done" << ", n: " << n << endl;
void *ret = nullptr;
n = pthread_join(tid, &ret);
cout << "main thread join done" << " n: " << n << ", thread return: " << (int64_t)ret << endl;
return 0;
}
线程如果是被分离的,该线程可以被取消,但是不能被等待
在Linux或多线程编程环境中,线程等待通常指的是一个线程暂停其执行,直到满足某个特定条件或另一个线程完成某个任务后再继续执行
pthread_join:
int pthread_join(pthread_t thread, void **value_ptr);
参数:
thread
:线程IDvalue_ptr
:它指向一个指针,后者指向线程的返回值代码示例:
void *ThreadRoutine(void *args)
{
string threadname = static_cast<const char*>(args);
int cnt = 5;
while(cnt--)
{
cout << "new thread -> name: " << threadname << endl;
sleep(1);
}
cout << "other thread done" << endl;
// return nullptr;
pthread_exit(nullptr);
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread_1");
sleep(10);
int n = pthread_join(tid, nullptr);
cout << "main thread done" << " n: " << n << endl;
sleep(5);
return 0;
}
如果我们想获取线程的返回值,我们要注意
pthread_join
的第二个参数是void **
类型,而ThreadRoutine
的返回值为void *
,因此我们要对格外注意
获取线程的返回值:
void *ThreadRoutine(void *args)
{
string threadname = static_cast<const char*>(args);
int cnt = 5;
while(cnt--)
{
cout << "new thread -> name: " << threadname << endl;
sleep(1);
}
cout << "other thread done" << endl;
// return nullptr;
return (void *)"thread_1 done";
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread_1");
void *ret = nullptr;
int n = pthread_join(tid, &ret); // 注意这里要&ret
cout << "main thread done" << " n: " << n << "thread done and return: "<< (const char*)ret << endl;
return 0;
}
分离线程是多线程编程中的一个重要概念,它指的是将一个线程从主线程或创建它的线程中分离出来,使其能够独立运行,并且不再需要其他线程使用特定的函数(如
pthread_join()
)来等待其结束
pthread_detach:
int pthread_detach(pthread_t thread);
参数:
thread
是你想要分离的线程的标识符(线程ID)返回值:如果成功,pthread_detach
返回 0。如果失败,它返回一个错误码
代码示例:(在线程分离后等待线程)
// 线程分离
void *ThreadRoutine(void *args)
{
string threadname = static_cast<const char*>(args);
int cnt = 5;
while(cnt--)
{
cout << "new thread -> name: " << threadname << endl;
sleep(1);
}
cout << "other thread done" << endl;
return nullptr;
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread_1");
sleep(1);
pthread_detach(tid);
int n = pthread_join(tid, nullptr);
cout << "main thread done" << " n: " << n << endl;
return 0;
}
在线程分离后等待线程,线程会直接返回一个错误码
线程ID本质是一个地址
void *ThreadRoutine(void *args)
{
string threadname = static_cast<const char*>(args);
while(1)
{
cout << "new thread -> name: " << threadname << endl;
sleep(1);
}
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread_1");
cout << "tid: " << tid << endl;
while(1)
{
cout << "I am a main thread" << endl;
sleep(1);
}
return 0;
}
pthread_self:
功能:可以获得线程自身的ID
pthread_t pthread_self(void);
返回值:
pthread_self
函数返回一个类型为pthread_t
的值,这个值唯一地标识了调用它的线程。pthread_t
通常是一个整数或结构体,用于表示线程标识符
代码示例:
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread_1");
cout << "pthread_t id: " << pthread_self() << endl;
return 0;
}
线程库要想管理线程,那么它必须要先被加载到地址空间中的mmap区域,线程库是共享的,内部要管理整个系统的,多个用户启动的所有线程
对于Linux目前实现的NPTL实现而言,pthread_t类型的线程ID,本质就是一个进程地址空间上的一个地址,为了方便我们的库直接找到内存,而pthread_t ID就是pthread的首地址,pthread库要自己维护线程这块栈区
在探索Linux线程控制的旅程中,我们不仅解锁了并发编程的强大潜力,还深刻理解了线程作为操作系统调度基本单位的核心价值。从线程的创建与终止巧妙运用,再到线程属性的精细调整,每一步都充满了挑战与收获
通过本文的引导,希望每位读者都能掌握一套系统化的线程控制方法论,无论是对于初学者踏入并发编程的大门,还是对于经验丰富的开发者深化对Linux线程机制的理解,都能有所裨益。记住,技术虽不断进步,但对基础概念的深刻理解永远是创新与优化的基石
未来,随着多核处理器架构的普及和云计算、大数据等领域的快速发展,Linux线程控制的重要性将愈发凸显。它不仅是构建高性能应用的必备技能,更是深入理解现代操作系统内部机制的关键一环。让我们带着这份知识与经验,继续在技术的海洋中航行,不断探索、实践与创新,共同迎接更加辉煌的技术未来
愿每位程序员都能在并发编程的世界里,编织出属于自己的精彩篇章!
希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行! 谢谢大家支持本篇到这里就结束了,祝大家天天开心!