Linux多线程基础函数使用

简介: Linux多线程基础函数使用

前言

本篇文章继续讲解Linux中多线程基础函数的使用。

一、pthread_self函数

pthread_self()是一个用于获取当前线程ID的函数,它属于POSIX线程库(pthread)提供的函数之一。

pthread_self()函数的原型为:

pthread_t pthread_self(void);

该函数在调用时不需要传入参数,它会返回当前线程的线程ID(pthread_t类型的值)。

线程ID是一个用于标识线程的唯一值,它在创建线程时由系统自动生成。通过pthread_self()函数,我们可以在线程内部获取当前线程的ID,以便后续的操作或标识。

下面是该函数的一些特点和使用方法:

1.pthread_self()函数返回的线程ID是一个不透明的数据类型(pthread_t),它实际上是一个指向线程ID结构体的指针。

2.线程ID通常用于线程的管理、线程间的通信和同步等操作。比如,我们可以使用线程ID来判断当前线程是否为目标线程,或者将线程ID传递给其他线程进行通信。

3.pthread_self()函数通常在线程内部调用,用于获取当前线程的ID。每个线程都可以通过该函数获取自己的线程ID,而不需要其他线程的参与。

示例代码如下:

#include <pthread.h>
#include <stdio.h>
void* threadFunction(void* arg) {
    pthread_t tid = pthread_self();
    printf("Thread ID: %lu\n", tid);
    // 线程的其他逻辑
    return NULL;
}
int main() {
    pthread_t thread;
    pthread_create(&thread, NULL, threadFunction, NULL);
    pthread_join(thread, NULL);
    return 0;
}

二、pthread_exit函数

pthread_exit()是一个线程终止函数,用于在线程内部显式地退出线程并返回终止状态。

pthread_exit()的函数原型为:

void pthread_exit(void* value_ptr);

参数value_ptr是一个指向线程的返回值的指针。它可以用于向等待该线程的其他线程传递一个返回值。如果不需要传递返回值,可以将value_ptr设置为NULL。

当调用pthread_exit()时,当前线程会立即终止,并将value_ptr指向的值作为线程的终止状态传递给等待该线程的其他线程。如果不等待线程退出,它的终止状态将被丢弃。

与之相反,如果在主线程中调用exit()函数或者从线程函数中返回,会导致整个进程的退出,而不仅仅是终止一个线程。

下面是一个使用pthread_exit()函数的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* threadFunction(void* arg) {
    int* value_ptr = (int*)arg; // 传入的参数作为返回值
    printf("Thread function executed\n");
    // 结束线程,并返回传入的值
    pthread_exit((void*)value_ptr);
}
int main() {
    pthread_t thread;
    int retVal = 42;
    pthread_create(&thread, NULL, threadFunction, (void*)&retVal);
    // 等待子线程结束,并获取其返回值
    void* exitStatus;
    pthread_join(thread, &exitStatus);
    int* threadRetVal = (int*)exitStatus;
    // 输出子线程的返回值
    printf("Thread exit status: %d\n", *threadRetVal);
    return 0;
}

在上述示例中,线程函数threadFunction接收一个整数参数作为返回值,并使用pthread_exit()将该值返回给主线程。主线程通过pthread_join()等待子线程的结束,并获取其返回值,最后打印出子线程的返回值。

总结起来,pthread_exit()函数允许线程在任何时候显式地退出,并传递一个终止状态给等待该线程的其他线程。这对于线程的管理和协作非常有用。

三、pthread_cancel函数

pthread_cancel()函数是一个用于取消线程执行的函数,它允许一个线程(调用者线程)请求取消另一个线程的执行。

pthread_cancel()的函数原型为:

#include <pthread.h>
int pthread_cancel(pthread_t thread);

参数thread是被取消的目标线程的线程ID(pthread_t类型)。函数返回一个整数值,表示取消操作的结果。如果成功取消线程,则返回0,否则返回一个非零的错误代码。

pthread_cancel()函数的行为是异步的,也就是说,当调用pthread_cancel()函数后,目标线程将会被立即请求取消,但取消的具体时间点取决于目标线程的状态和实现的策略。

在请求取消一个线程时,pthread_cancel()函数会向目标线程发送一个取消请求,目标线程可以通过在适当的位置检查取消状态来决定是否响应取消请求。目标线程可以有三种方式响应取消请求:

1.线程忽略取消请求:目标线程可以通过调用pthread_setcancelstate()函数将取消状态设置为PTHREAD_CANCEL_DISABLE,从而忽略取消请求。

2.线程立即取消自身:目标线程可以在适当的位置主动调用pthread_exit()函数来立即取消自身。

3.线程响应取消请求:目标线程可以在适当的位置检查取消状态,并通过执行相应的清理操作来响应取消请求。

需要注意的是,pthread_cancel()函数并不保证目标线程会立即被取消,因为线程的取消响应还取决于目标线程中的取消点(cancellation point)。取消点是指线程在执行期间主动检查取消状态的位置,例如I/O操作、互斥锁的获取和释放等,这些操作通常是线程可能长时间阻塞的地方。只有当目标线程达到一个取消点时才会响应取消请求。

使用pthread_cancel()函数时,需要注意以下几点:

1.目标线程必须能够响应取消请求,即在适当的位置检查取消状态并执行相应的清理操作。

2.当目标线程被取消后,取消点以后的代码将不会被执行。

3.取消一个线程可能引发资源泄漏或数据不一致的问题,因此在使用pthread_cancel()时,需要谨慎考虑线程的设计和取消点的位置。

总结来说,pthread_cancel()函数用于请求取消一个线程的执行,但实际的取消时间和行为取决于目标线程的检查点和响应策略。在使用该函数时,需要仔细设计线程的响应取消请求的逻辑,以确保正确的线程进行清理和资源释放操作。

示例代码:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void* threadFunction(void* arg) {
    // 设置取消状态为允许取消
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    // 设置取消类型为异步取消
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    printf("Thread started\n");
    while (1) {
        printf("Thread is running\n");
        sleep(1);
    }
    printf("Thread finished\n");
    return NULL;
}
int main() {
    pthread_t thread;
    pthread_create(&thread, NULL, threadFunction, NULL);
    // 主线程休眠5秒后取消子线程
    sleep(5);
    pthread_cancel(thread);
    // 等待子线程结束
    pthread_join(thread, NULL);
    printf("Main thread finished\n");
    return 0;
}

四、pthread_detach

pthread_detach函数用于将一个线程标记为分离状态,从而使得线程的资源在其终止时可以自动释放,而不需要其他线程调用pthread_join函数来等待其终止。这样可以避免出现僵尸线程(zombie thread),从而简化了对线程资源的管理。

函数原型如下:

int pthread_detach(pthread_t thread);

pthread_detach函数接受一个pthread_t类型的参数thread,表示要标记为分离状态的线程。

下面是一个示例代码,演示pthread_detach函数的使用:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void* threadFunction(void* arg) {
    printf("Thread started\n");
    sleep(5);
    printf("Thread finished\n");
    return NULL;
}
int main() {
    pthread_t thread;
    pthread_create(&thread, NULL, threadFunction, NULL);
    // 将子线程标记为分离状态
    pthread_detach(thread);
    printf("Main thread finished\n");
    return 0;
}

在上述示例代码中,我们创建了一个子线程,并通过pthread_detach函数将其标记为分离状态。在主线程中,我们没有使用pthread_join函数来等待子线程的终止,而是直接输出Main thread finished并结束主线程。

当子线程执行完毕后,其资源会自动被系统回收,不再存在僵尸线程。因此,我们不需要显示地等待子线程的终止。

需要注意的是,一旦将一个线程标记为分离状态,就不能再通过pthread_join函数对该线程进行等待操作。如果尝试使用pthread_join等待一个已标记为分离状态的线程,将会返回EINVAL错误。

分离状态的线程可以通过调用pthread_self函数来获取其自身线程号,但是无法通过pthread_equal函数来比较两个线程号是否相等。

pthread_detach函数通过将线程标记为分离状态,使得线程退出后的资源自动释放,而无需其他线程进行等待。这在某些场景下可以简化线程的管理。

总结

本篇文章就讲解到这里。


相关文章
|
12月前
|
存储 Linux API
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
在计算机系统的底层架构中,操作系统肩负着资源管理与任务调度的重任。当我们启动各类应用程序时,其背后复杂的运作机制便悄然展开。程序,作为静态的指令集合,如何在系统中实现动态执行?本文带你一探究竟!
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
|
10月前
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
358 67
|
存储 Linux
linux中的目录操作函数
本文详细介绍了Linux系统编程中常用的目录操作函数,包括创建目录、删除目录、读取目录内容、遍历目录树以及获取和修改目录属性。这些函数是进行文件系统操作的基础,通过示例代码展示了其具体用法。希望本文能帮助您更好地理解和应用这些目录操作函数,提高系统编程的效率和能力。
403 26
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
241 26
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
265 17
|
Linux
【Linux】System V信号量详解以及semget()、semctl()和semop()函数讲解
System V信号量的概念及其在Linux中的使用,包括 `semget()`、`semctl()`和 `semop()`函数的具体使用方法。通过实际代码示例,演示了如何创建、初始化和使用信号量进行进程间同步。掌握这些知识,可以有效解决多进程编程中的同步问题,提高程序的可靠性和稳定性。
796 19
|
Linux Android开发 开发者
linux m、mm、mmm函数和make的区别
通过理解和合理使用这些命令,可以更高效地进行项目构建和管理,特别是在复杂的 Android 开发环境中。
760 18
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
609 13
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
629 6
|
C++
C++ 多线程之线程管理函数
这篇文章介绍了C++中多线程编程的几个关键函数,包括获取线程ID的`get_id()`,延时函数`sleep_for()`,线程让步函数`yield()`,以及阻塞线程直到指定时间的`sleep_until()`。
357 0
C++ 多线程之线程管理函数