前言
本篇文章继续讲解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函数通过将线程标记为分离状态,使得线程退出后的资源自动释放,而无需其他线程进行等待。这在某些场景下可以简化线程的管理。
总结
本篇文章就讲解到这里。