第五章:线程相关函数

  1. 1. 线程的概念
    1. 1.1. pthread_equal(3)
    2. 1.2. pthread_self(3)
  2. 2. 线程的创建
    1. 2.1. pthread_create(3)
  3. 3. 线程的终止
    1. 3.1. pthread_exit(3)
    2. 3.2. pthread_join(3)
  4. 4. 栈的清理
    1. 4.1. pthread_cleanup_push(3)
    2. 4.2. pthread_cleanup_pop(3)
  5. 5. 线程的取消
    1. 5.1. pthread_cancel(3)
    2. 5.2. pthread_testcancel(3)
    3. 5.3. pthread_setcancelstate(3)
    4. 5.4. pthread_setcanceltype(3)
    5. 5.5. pthread_detach(3)

介绍线程相关的一些重要函数

注:标题中显示的函数数字表示该函数在man手册中所在章节(第2章的是系统调用函数,第3章的是标准函数)

线程的概念

线程就是一个正在运行的函数。(进程就是容器,用来承载线程)

POSIX线程是一套标准,而不是实现。

线程标识:pthread_t 中的”p”表示POSIX,数据类型不确定,因为各家实现不一样,有可能是整型,有可能是结构体,还有可能是typedef出来的指针类型。

ps axf:查看进程关系

ps axm:查看每个进程的线程

ps ax -L:以列表形式查看进程与线程关系;

-L: Show threads, possibly with LWP and NLWP columns.

m: Show threads after processes.

信号机制和多线程机制可以在小范围内混用,不建议大范围内混用。

pthread_equal(3)

在线程编程中,线程标识符是用来唯一标识一个线程的值,类似于进程ID(PID)用于唯一标识一个进程。pthread_equal() 函数用于比较两个线程标识符是否相等,从而判断两个线程是否是同一个线程。函数原型如下:

1
2
3
#include <pthread.h>

int pthread_equal(pthread_t t1, pthread_t t2);

参数说明:

  • thread1thread2:两个线程标识符,类型为pthread_t。这两个参数将被用来比较是否表示同一个线程。

函数返回值:

  • 如果thread1thread2表示同一个线程,函数返回值为非零值(通常为1)。
  • 如果thread1thread2表示不同的线程,函数返回值为0。

注意事项:

  • pthread_equal() 函数可以用来检查两个线程标识符是否相等,但并不是所有情况下都需要使用它。大多数情况下,你不需要直接比较线程标识符,而是通过线程同步机制来确保线程之间的正确协作。
  • 在实际编程中,尽量避免直接使用 pthread_equal() 来做逻辑判断,因为它可能会引入不必要的复杂性和风险。更好的方法是使用互斥锁、条件变量等线程同步机制来控制线程的执行顺序和协作。

pthread_self(3)

pthread_self() 函数用于获取当前调用线程的线程标识符。函数原型如下:

1
2
3
#include <pthread.h>

pthread_t pthread_self(void);

函数返回值:

  • 返回值是一个pthread_t 类型的值,表示调用线程的线程标识符。

注意事项:

  • pthread_self() 函数返回的线程标识符是一个内部表示,通常是一个指针或数字。在不同的操作系统和编译器中,它可能采用不同的方式来表示线程标识符。因此,最好不要将线程标识符作为具体的数值来进行比较或操作。

线程的创建

pthread_create(3)

pthread_create()函数用于创建一个新的线程,函数原型如下:

1
2
3
4
#include <pthread.h>

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

参数说明:

  • thread:指向 pthread_t 类型变量的指针,用于保存新线程的标识符。
  • attr:指向 pthread_attr_t 类型变量的指针,用于指定新线程的属性,例如线程的栈大小、线程优先级等。如果为 NULL,则使用默认线程属性。
  • start_routine:线程函数的指针,新线程将从这个函数开始执行
  • arg:传递给线程函数的参数。

函数返回值:

若成功,返回0;否则,返回错误编号(error number)。

On success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined. (man手册)

举个栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// pthread_create.c

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>

static void *thread_func(void *arg)
{
printf("The thread is working.\n");
return NULL;
}

int main(int argc, char **argv)
{
pthread_t tid;
int err;

puts("Begin!");
err = pthread_create(&tid, NULL, thread_func, NULL);
if (err)
{
fprintf(stderr, "pthread_create(): %s\n", strerror(err));
exit(1);
}
puts("End!");
exit(0);
}

编译运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ gcc pthread_create.c -pthread
$ ./a.out
Begin!
End!
$ ./a.out
Begin!
End!
The thread is working.
The thread is working.
$ ./a.out
Begin!
End!
The thread is working.

注:线程的调度取决于调度器策略

编译也可以通过包含以下内容的makefile文件来实现:

1
2
CFLAGS+=-pthread
LDFLAGS+=-pthread

不用写成类似于gcc pthread_create.c -pthread,直接make pthread_create即可。

线程的终止:

(1)线程从启动例程返回,返回值就是线程的退出码;

(2)线程可以被同一进程中的其他线程取消;

(3)线程调用pthread_exit()函数;(该函数会结束调用线程)

【man手册:】

The new thread terminates in one of the following ways:

  • It calls pthread_exit(3), specifying an exit status value that is available to another thread in the same process that calls pthread_join(3).

  • It returns from start_routine(). This is equivalent to calling pthread_exit(3) with the value supplied in the return statement.

  • It is canceled (see pthread_cancel(3)).

  • Any of the threads in the process calls exit(3), or the main thread performs a return from main(). This causes the termination of all threads in the process.

线程的终止

pthread_exit(3)

pthread_exit()函数用于终止当前线程的执行,并返回一个退出状态给线程的调用者。它允许线程在完成任务或遇到特定条件时自行终止,而不影响其他线程。函数原型如下:

1
2
3
#include <pthread.h>

void pthread_exit(void *retval);

参数说明:

  • retval:一个指向任意类型数据的指针,表示线程的退出状态。在多线程环境下,线程的退出状态可以是一个任意类型的数据,用于向其他线程传递信息。

注意事项:

  1. 使用 pthread_exit() 函数可以避免线程突然终止,从而防止线程资源泄漏和未完成的操作。
  2. 在调用 pthread_exit() 函数之后,当前线程会立即终止,并不会执行 pthread_join() 函数等待其他线程完成。
  3. 被终止的线程的资源会被系统回收,但其他线程仍会继续运行。
  4. 在多线程程序中,如果某个线程使用 pthread_exit() 终止了,整个程序可能还会继续执行,直到所有线程都完成或被终止。

举个栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>

static void *thread_func(void *arg)
{
int n = *((int *)arg);

printf("Thread %d started.\n", n);
for (int i = 0; i < n; i++)
{
printf(" Thread [%d]: %d\n", n, i);
}
printf("Thread %d finished.\n", n);

pthread_exit(NULL);
}

int main()
{
pthread_t tid1, tid2;
int ret1, ret2;
int n1 = 3, n2 = 5;

ret1 = pthread_create(&tid1, NULL, thread_func, &n1);
if (ret1)
{
fprintf(stderr, "pthread_create(): %s\n", strerror(ret1));
exit(1);
}

ret2 = pthread_create(&tid2, NULL, thread_func, &n2);
if (ret2)
{
fprintf(stderr, "pthread_create(): %s\n", strerror(ret2));
exit(1);
}

pthread_join(tid1, NULL);
pthread_join(tid2, NULL);

printf("Main thread finished.\n");
exit(0);
}

编译运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
Thread 3 started.
Thread [3]: 0
Thread [3]: 1
Thread [3]: 2
Thread 3 finished.
Thread 5 started.
Thread [5]: 0
Thread [5]: 1
Thread [5]: 2
Thread [5]: 3
Thread [5]: 4
Thread 5 finished.
Main thread finished.

pthread_join(3)

pthread_join()函数用于等待指定的线程结束,并获取它的退出状态。函数原型如下:

1
2
3
#include <pthread.h>

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

参数说明:

  • thread:要等待的线程的标识符,通常是通过调用 pthread_create() 函数创建的线程。
  • retval:一个指向指针的指针,用于存储被等待线程的退出状态。这个参数允许线程传递一个指向任意数据类型的指针作为退出状态。

函数返回值:

On success, pthread_join() returns 0; on error, it returns an error number.

注意事项:

  1. 如果不关心线程的退出状态,可以将 retval 参数设置为 NULL。
  2. 如果指定的线程已经结束,那么 pthread_join() 函数会立即返回,并返回 0 作为函数值。如果指定的线程还未结束,那么 pthread_join() 函数会一直阻塞,直到线程结束为止。

注:pthread_join()函数功能类似于wait()函数,收尸。

在多线程编程中,线程的退出状态通常用来表示线程的执行结果,可以通过 pthread_exit() 函数返回给线程的调用者,或者通过 pthread_join() 函数获取。在某些情况下,我们可能需要在线程中传递一些复杂的数据结构,如结构体指针等,来描述线程的执行结果。此时,我们可以将这些数据结构作为指针传递给线程函数,让线程函数负责修改这些数据结构,并通过 pthread_exit() 函数或全局变量等方式将其返回给线程的调用者。

举个栗子:

以下是一个简单的例子,演示如何在线程中传递指针来描述线程的执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

typedef struct
{
int id;
int count;
} ThreadData;

void *thread_func(void *arg)
{
ThreadData *data = (ThreadData *)arg;
printf("Thread %d started.\n", data->id);

// 模拟线程执行
for (int i = 1; i <= data->count; i++)
{
printf(" Thread %d: %d\n", data->id, i);
}

// 修改数据结构的值
data->count *= data->count;

// 返回线程的退出状态
pthread_exit(NULL);
}

int main()
{
int ret1, ret2;
pthread_t tid1, tid2;
ThreadData data1 = {1, 3}, data2 = {2, 5};

// 创建两个新线程
ret1 = pthread_create(&tid1, NULL, thread_func, &data1);
ret2 = pthread_create(&tid2, NULL, thread_func, &data2);

if (ret1 != 0 || ret2 != 0)
{
printf("Failed to create threads!\n");
exit(EXIT_FAILURE);
}

// 等待两个线程结束
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);

printf("Thread 1 count: %d\n", data1.count);
printf("Thread 2 count: %d\n", data2.count);

printf("Main thread finished.\n");
return 0;
}

编译运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
Thread 1 started.
Thread 1: 1
Thread 1: 2
Thread 1: 3
Thread 2 started.
Thread 2: 1
Thread 2: 2
Thread 2: 3
Thread 2: 4
Thread 2: 5
Thread 1 count: 9
Thread 2 count: 25
Main thread finished.

栈的清理

pthread_cleanup_push(),pthread_cleanup_pop() 都是宏,作用类似于钩子函数。

注:gcc xxx.c -E可以判断xxx.c文件中哪些是宏/条件编译,预处理后剩下的内容。

NAME

pthread_cleanup_push, pthread_cleanup_pop - push and pop thread cancellation clean-up handlers

SYNOPSIS

#include <pthread.h>

void pthread_cleanup_push(void (*routine)(void *), void *arg);

void pthread_cleanup_pop(int execute);

Compile and link with -pthread.

DESCRIPTION

These functions manipulate the calling thread’s stack of thread-cancellation clean-up handlers. A clean-up handler is a function that is automatically executed when a thread is canceled (or in various other circumstances described below); it might, for example, unlock a mutex so that it becomes available to other threads in the process.

The pthread_cleanup_push() function pushes routine onto the top of the stack of clean-up handlers. When routine is later invoked, it will be given arg as its argument.

The pthread_cleanup_pop() function removes the routine at the top of the stack of clean-up handlers, and optionally executes it if execute is nonzero.

A cancellation clean-up handler is popped from the stack and executed in the following circumstances:

1. When a thread is canceled, all of the stacked clean-up handlers are popped and executed in the reverse of the order in which they were pushed onto the stack.

2. When a thread terminates by calling pthread_exit(3), all clean-up handlers are executed as described in the preceding point. (Clean-up handlers are not called if the thread terminates by performing a return from the thread start function.)

3. When a thread calls pthread_cleanup_pop() with a nonzero execute argument, the top-most clean-up handler is popped and executed.

POSIX.1 permits pthread_cleanup_push() and pthread_cleanup_pop() to be implemented as macros that expand to text containing ‘{‘ and ‘}’, respectively. For this reason, the caller must ensure that calls to these functions are paired within the same function, and at the same lexical nesting level. (In other words, a clean-up handler is established only during the execution of a specified section of code.)

RETURN VALUE

These functions do not return a value.

在指定的代码段执行期间才会建立清理处理程序。在执行过程中,可以使用 pthread_cleanup_push() 函数将清理处理程序压入堆栈,并在代码段执行结束时使用 pthread_cleanup_pop() 函数将其弹出。这种机制确保了清理处理程序只在特定代码段的执行过程中存在,并在其执行结束后自动弹出。这种机制在多线程编程中非常有用,可以确保线程在任何情况下都能够正常地终止并释放资源。

pthread_cleanup_push(3)

pthread_cleanup_push() 函数用于为线程设置清理处理程序(clean-up handler)。该函数可以将一个清理处理程序绑定到线程,当线程退出时,清理处理程序会被调用。函数原型如下:

1
2
3
#include <pthread.h>

void pthread_cleanup_push(void (*routine)(void *), void *arg);

参数说明:

  • routine:一个函数指针,指向清理处理程序函数,这个函数在线程退出时会被调用。它的原型应该是 void function_name(void *arg)
  • arg:传递给清理处理程序函数的参数,类型是void *。这可以是指向某个资源或状态的指针,以便在清理处理程序中进行适当的操作。

pthread_cleanup_pop(3)

pthread_cleanup_pop() 函数用于指定清理处理程序的执行条件。函数原型如下:

1
2
3
#include <pthread.h>

void pthread_cleanup_pop(int execute);

参数说明:

  • execute:一个整数值,用于指定是否执行清理处理程序。非零值表示执行,零值表示不执行。

注意事项:

  • pthread_cleanup_push() 函数必须与 pthread_cleanup_pop() 成对使用。每次调用 pthread_cleanup_push() 函数都应该紧接着调用相应的 pthread_cleanup_pop() 函数。
  • 当线程调用pthread_exit()、pthread_cancel()、pthread_cleanup_pop() 或者线程函数返回时,绑定在该线程上的清理处理程序会被按照它们被创建时的相反顺序执行。
  • 清理处理程序的执行条件是由线程库在特定条件下自动执行的,而不是由线程程序员显式调用的。清理处理程序通常用于资源释放、内存清理等工作,以确保在线程退出时不会造成资源泄漏。

举个栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// cleanup.c

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>

static void cleanup_func(void *arg)
{
puts(arg);
}

static void *func(void *p)
{
puts("The thread is working!");

pthread_cleanup_push(cleanup_func, "cleanup:1");
pthread_cleanup_push(cleanup_func, "cleanup:2");
pthread_cleanup_push(cleanup_func, "cleanup:3");

puts("push over!");

pthread_cleanup_pop(1);
pthread_cleanup_pop(1);
pthread_cleanup_pop(1);

pthread_exit(NULL);
}

int main()
{
pthread_t tid;
int err;

puts("Begin.");
err = pthread_create(&tid, NULL, func, NULL);
if (err)
{
fprintf(stderr, "pthread_create():%s\n", strerror(err));
exit(1);
}
pthread_join(tid, NULL);
puts("End.");

exit(0);
}

编译运行结果如下:

1
2
3
4
5
6
7
8
9
10
$ make cleanup
cc -pthread -pthread cleanup.c -o cleanup
$ ./cleanup
Begin.
The thread is working!
push over!
cleanup:3
cleanup:2
cleanup:1
End.

线程的取消

pthread_cancel(3)

注:要结束正在运行的线程,先把线程取消,再收尸。就跟wait()函数给进程收尸一样,正在运行的内容是没办法收尸收回来的。

调用 pthread_cancel() 函数会向指定的线程发送取消请求,但并不保证该线程会立即退出,而是在接下来的某个取消点(cancellation point)执行取消操作。线程会在适当的时候检查取消请求,并调用相应的清理处理函数。这些清理处理函数可以通过调用 pthread_cleanup_push() 和 pthread_cleanup_pop() 函数来注册。

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.

DESCRIPTION

The pthread_cancel() function sends a cancellation request to the thread thread. Whether and when the target thread reacts to the cancellation request depends on two attributes that are under the control of that thread: its cancelability state and type.

A thread’s cancelability state, determined by pthread_setcancelstate(3), can be enabled (the default for new threads) or disabled. If a thread has disabled cancellation, then a cancellation request remains queued until the thread enables cancellation. If a thread has enabled cancellation, then its cancelability type determines when cancellation occurs.

A thread’s cancellation type, determined by pthread_setcanceltype(3), may be either asynchronous or deferred (the default for new threads). Asynchronous cancelability means that the thread can be canceled at any time (usually immediately, but the system does not guarantee this). Deferred cancelability means that cancellation will be delayed until the thread next calls a function that is a cancellation point. A list of functions that are or may be cancellation points is provided in pthreads(7).

When a cancellation requested is acted on, the following steps occur for thread (in this order):

1. Cancellation clean-up handlers are popped (in the reverse of the order in which they were pushed) and called. (See pthread_cleanup_push(3).)

2. Thread-specific data destructors are called, in an unspecified order. (See pthread_key_create(3).)

3. The thread is terminated. (See pthread_exit(3).)

The above steps happen asynchronously with respect to the pthread_cancel() call; the return status of pthread_cancel() merely informs the caller whether the cancellation request was successfully queued.

After a canceled thread has terminated, a join with that thread using pthread_join(3) obtains PTHREAD_CANCELED as the thread’s exit status. (Joining with a thread is the only way to know that cancellation has completed.)

RETURN VALUE

On success, pthread_cancel() returns 0; on error, it returns a nonzero error number.

取消有2种状态:允许和不允许。

允许取消可分为:异步cancel;推迟cancel(默认)-> 推迟至cancel点再响应

cancel点:POSIX定义的cancel点,都是可能引发阻塞的系统调用。而非系统调用的内容是不是cancel点,各个平台定义有所区别。

注意事项:

  • pthread_cancel() 函数并不保证线程会立即终止,而是发送一个取消请求。实际的取消发生可能会受到线程当前的状态和取消点的影响。
  • 线程可以选择是否响应取消请求,它可以在取消点进行响应,也可以选择忽略取消请求。
  • 线程可以通过调用pthread_setcancelstate() 函数来设置线程是否允许取消,以及在取消点是否响应取消。

举个栗子:

以下代码片段中,如果在第一次open()操作执行成功后,第二次open()操作执行前被中断,那close()操作将无法执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fd1 = open();
if(fd1 < 0)
{
perror();
exit(1);
}

fd2 = open();
if(fd2 < 0)
{
perror();
exit(1);
}

close(fd1);
close(fd2);

可以挂钩子函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fd1 = open();
if(fd1 < 0)
{
perror();
exit(1);
}
----> pthread_cleanup_push(); -> close(fd1);

fd2 = open();
if(fd2 < 0)
{
perror();
exit(1);
}
----> pthread_cleanup_push(); -> close(fd2);

如果前面成功了,但刚好在挂钩子函数之前就被取消了,这种情况是不会发生的。

pthread_testcancel(3)

NAME
pthread_testcancel - request delivery of any pending cancellation request

SYNOPSIS
#include <pthread.h>

void pthread_testcancel(void);

Compile and link with -pthread.

DESCRIPTION
Calling pthread_testcancel() creates a cancellation point within the calling thread, so that a thread that is otherwise executing code that contains no cancellation points will respond to a cancellation request.

If cancelability is disabled (using pthread_setcancelstate(3)), or no cancellation request is pending, then a call to pthread_testcancel() has no effect.

RETURN VALUE
This function does not return a value. If the calling thread is canceled as a consequence of a call to this function, then the function does not return.

注:在多线程编程中,取消请求是用来请求终止一个线程的操作,但是实际终止时间是由线程在取消点检查取消请求后决定的。

pthread_testcancel() 函数通常被用作取消点(cancellation point),检查是否有取消请求被发送。如果有取消请求,则线程会在此处终止执行,之后的代码将不再执行。函数原型如下:

1
2
3
#include <pthread.h>

void pthread_testcancel(void);

注意事项:

  • 在程序中使用pthread_testcancel() 函数时,通常需要与pthread_setcancelstate() 函数和pthread_setcanceltype() 函数一起使用,以确保线程在取消点检查取消请求。

举个栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

static void *thread_function(void *arg)
{
int i = 0;

while (1)
{
printf("Thread is running...\n");
i++;
if (i == 5)
{
pthread_testcancel(); // 作为取消点,检查取消请求

// 此后的代码不会被执行,因为在取消点检查到取消请求后线程会终止
}
sleep(1);
}

pthread_exit(NULL);
}

int main()
{
pthread_t tid;

pthread_create(&tid, NULL, thread_function, NULL);
sleep(5); // 让线程运行一段时间

// 发送取消请求
if (pthread_cancel(tid) != 0)
{
perror("pthread_cancel");
exit(1);
}

pthread_join(tid, NULL);

printf("Main thread done.\n");

exit(0);
}
1
2
3
4
5
6
Thread is running...
Thread is running...
Thread is running...
Thread is running...
Thread is running...
Main thread done.

在上面的示例中,pthread_testcancel() 函数被用作取消点,用于在线程中检查是否有取消请求。在调用这个函数后,如果有取消请求,线程将终止。

pthread_setcancelstate(3)

NAME

pthread_setcancelstate, pthread_setcanceltype - set cancelability state and type

SYNOPSIS

#include <pthread.h>

int pthread_setcancelstate(int state, int *oldstate);

int pthread_setcanceltype(int type, int *oldtype);

Compile and link with -pthread.

DESCRIPTION

The pthread_setcancelstate() sets the cancelability state of the calling thread to the value given in state. The previous cancelability state of the thread is returned in the buffer pointed to by oldstate. The state argument must have one of the following values:

PTHREAD_CANCEL_ENABLE The thread is cancelable. This is the default cancelability state in all new threads, including the initial thread. The thread’s cancelability type determines when a cancelable thread will respond to a cancellation request.

PTHREAD_CANCEL_DISABLE The thread is not cancelable. If a cancellation request is received, it is blocked until cancelability is enabled.

The pthread_setcanceltype() sets the cancelability type of the calling thread to the value given in type. The previous cancelability type of the thread is returned in the buffer pointed to by oldtype. The type argument must have one of the following values:

PTHREAD_CANCEL_DEFERRED A cancellation request is deferred until the thread next calls a function that is a cancellation point (see pthreads(7)). This is the default cancelability type in all new threads, including the initial thread.

PTHREAD_CANCEL_ASYNCHRONOUS The thread can be canceled at any time. (Typically, it will be canceled immediately upon receiving a cancellation request, but the system doesn’t guarantee this.)

The set-and-get operation performed by each of these functions is atomic with respect to other threads in the process calling the same function.

RETURN VALUE

On success, these functions return 0; on error, they return a nonzero error number.

pthread_setcancelstate() 函数用于设置线程的取消状态。线程可以设置是否允许取消请求(cancellation request)对其进行取消。函数原型如下:

1
2
3
#include <pthread.h>

int pthread_setcancelstate(int state, int *oldstate);

参数说明:

  • state:一个整数值,表示要设置的取消状态。可以是以下值之一:
    • PTHREAD_CANCEL_ENABLE:允许取消请求(默认值)。
    • PTHREAD_CANCEL_DISABLE:禁止取消请求。
  • oldstate:一个指向整数的指针,用于存储之前的取消状态。如果不关心之前的状态,可以将此参数设置为 NULL。

函数返回值:

  • 若成功设置取消状态,函数返回值为0;若发生错误,返回一个非零的错误码。

注意事项:

  • 取消状态仅影响线程是否对取消请求进行响应,实际的取消点和取消类型也会影响线程的终止。
  • 在调用 pthread_create() 创建线程之前,可以使用 pthread_setcancelstate() 来设置线程的取消状态。

pthread_setcanceltype(3)

pthread_setcanceltype() 函数用于设置线程的取消类型。线程的取消类型决定了在取消点检查取消请求时,线程如何响应取消请求。函数原型如下:

1
2
3
#include <pthread.h>

int pthread_setcanceltype(int type, int *oldtype);

参数说明:

  • type:一个整数值,表示要设置的取消类型。可以是以下值之一:
    • PTHREAD_CANCEL_ASYNCHRONOUS:立即响应取消请求。
    • PTHREAD_CANCEL_DEFERRED:只有在下一个取消点时响应取消请求(默认值)。
  • oldtype:一个指向整数的指针,用于存储之前的取消类型。如果不关心之前的类型,可以将此参数设置为 NULL。

函数返回值:

  • 若成功设置取消类型,函数返回值为0;若发生错误,返回一个非零的错误码。

注意事项:

  • 取消类型会影响线程在取消点检查取消请求时的响应,以及线程是否会在取消点终止执行。
  • 在调用 pthread_create() 创建线程之前,可以使用 pthread_setcanceltype() 来设置线程的取消类型。

pthread_detach(3)

NAME

pthread_detach - detach a thread

SYNOPSIS

#include <pthread.h>

int pthread_detach(pthread_t thread);

Compile and link with -pthread.

DESCRIPTION

The pthread_detach() function marks the thread identified by thread as detached. When a detached thread terminates, its resources are automatically released back to the system without the need for another thread to join with the terminated thread.

Attempting to detach an already detached thread results in unspecified behavior.

RETURN VALUE

On success, pthread_detach() returns 0; on error, it returns an error number.

ERRORS

EINVAL thread is not a joinable thread.

ESRCH No thread with the ID thread could be found.

在线程编程中,有两种状态:分离状态和非分离状态。分离状态的线程在退出后会自动释放资源,而非分离状态的线程需要通过pthread_join() 来获取返回值并释放资源。

pthread_detach() 函数用于将一个线程标记为“分离状态”,从而使得线程在退出时能够自动释放其资源,无需显式调用 pthread_join() 来等待其它线程获取返回值。函数原型如下:

1
2
3
#include <pthread.h>

int pthread_detach(pthread_t thread);

参数说明:

  • thread:要被标记为分离状态的线程的标识符,类型为pthread_t

函数返回值:

  • 若成功将线程标记为分离状态,函数返回值为0;若发生错误,返回一个非零的错误码。

注意事项:

  • 只能对还没有被其他线程调用 pthread_join() 的线程进行分离操作。
  • 在线程标记为分离状态之后,不能再次对其进行分离或者非分离操作。