抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

pthread_create 创建线程

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
55
56
/*************************************************************************
> File Name: pthread_create.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年05月30日 星期一 10时33分57秒
************************************************************************/


/*
一般情况下, main 函数所在的线程我们称之为主线程(main线程),其余创建的线程称之为子线程。
程序中默认只有一个进程,fork()函数调用,2进行
程序中默认只有一个线程,pthread_create(函数调用),2个线程

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
- 功能: 创建一个子线程
- 参数:
- thread: 传出参数,线程创建成功,子线程的线程ID被写到该变变量当中
- attr: 设置线程的属性, 一般使用默认值,NULL
- start_routine: 函数指针,这个函数是子线程需要处理的逻辑代码
- atg: 给第三个参数使用的,传参
- 返回值:
成功返回 0
失败返回 错误号,和之前的errno不太一样
获取错误号的信息: char strerror(int errnum)
*/


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

void *callback(void *arg) {
printf("child thread...\n");
printf("arg value:%d \n", *(int *)arg);
return NULL;
}

int main() {

pthread_t tid;
int num = 10;
// 创建一个子线程
int ret = pthread_create(&tid, NULL, callback, (void *)&num);
if(ret != 0) {
char * errstr = strerror(ret);
printf("error : %s \n", errstr);
}

for(int i = 0; i < 5; i++) {
printf("%d\n", i);
}
sleep(1);
return 0;
}

主线程和子线程其实是交替执行的

pthread_exit() 终止线程 - pthread_self() 获取当前的线程的线程ID

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
/*************************************************************************
> File Name: pthread_exit.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年05月30日 星期一 14时30分18秒
************************************************************************/

/*

#include <pthread.h>
void pthread_exit(void *retval);
功能: 终止一个线程,在那个线程中调用,就表示终止那个那个线程
参数:
retval:需要传递一个指针,作为一个返回值,返回值可以在pthread_join()中获取到

pthread_t thread_self(void);
功能: 获取当前的线程的线程ID

*/


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

void *callback(void *arg) {
printf("child thread id : %ld\n", pthread_self());
return NULL; // pthread_exit(null);
}

int main() {

// 创建一个线程
pthread_t tid;
int ret = pthread_create(&tid, NULL, callback, NULL);
if(ret != 0) {
char *errstr = strerror(ret);
printf("error : %s\n", errstr);
}

for(int i = 0; i < 5; i++) {
printf("%d\n", i);
}

printf("tid : %ld, main thread id : %ld\n", tid, pthread_self());

// 让主线程退出,当主线程退出时,不影响其他正常运行的线程
pthread_exit(NULL);

// 运行之后可以看出 printf 和 return 0都没执行 所以说????
printf("main thread exit \n");

return 0;
}

pthread_join() 链接已终止的进程(回收子线程)

回收子线程测试阻塞

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
55
56
57
58
59
60
61
62
63
/*************************************************************************
> File Name: pthread_join.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年05月30日 星期一 17时54分48秒
************************************************************************/

/*
* #include <pthread.h>
* int pthread_join(pthread_t thread, void **retval);
* - 功能:和一个已经终止的线程进行链接
* 回收子线程的资源
* 这个函数是阻塞函数,调用一次只能回收一个子线程
* 一般在主线线程中使用
* - 参数:
* - thread: 需要回收的子线程的ID
* - retval: 接收子进程退出时的返回值
* - 返回值:
* 成功返回 0
* 失败返回 错误号
*/

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

void *callback(void* arg) {
printf("child thread id : %ld\n", pthread_self());
sleep(3);
return NULL;
}

int main() {

// 创建一个子线程
pthread_t tid;
int ret = pthread_create(&tid, NULL, callback, NULL);

if(ret != 0) {
char *errstr = strerror(ret);
printf("error : %s\n", errstr);
}

for(int i = 0; i < 5; i++) {
printf("%d \n", i);
}

printf("tid : %ld, main thread id : %ld\n", tid, pthread_self());

// 主线程调用pthread_join回收子进程资源 - 阻塞进程
ret = pthread_join(tid, NULL);
if(ret != 0) {
char *errstr = strerror(ret);
printf("error : %s\n", errstr);
}

printf("回收子线程的资源成功\n");

// 让主线程退出
pthread_exit(NULL);
return 0;
}
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/*************************************************************************
> File Name: pthread_join.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年05月30日 星期一 17时54分48秒
************************************************************************/

/*
* #include <pthread.h>
* int pthread_join(pthread_t thread, void **retval);
* - 功能:和一个已经终止的线程进行链接
* 回收子线程的资源
* 这个函数是阻塞函数,调用一次只能回收一个子线程
* 一般在主线线程中使用
* - 参数:
* - thread: 需要回收的子线程的ID
* - retval: 接收子进程退出时的返回值
* - 返回值:
* 成功返回 0
* 失败返回 错误号
*/

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

int value = 10;

void *callback(void* arg) {
printf("child thread id : %ld\n", pthread_self());
// sleep(3);
// return NULL;
// int value = 10; // 局部变量 - 因为在之前的图中可知栈空间是分层的所以你释放完时候下面输出的就是一个随机的值
pthread_exit((void *)&value); // 跟retrn (void *)&value

}

int main() {

// 创建一个子线程
pthread_t tid;
int ret = pthread_create(&tid, NULL, callback, NULL);

if(ret != 0) {
char *errstr = strerror(ret);
printf("error : %s\n", errstr);
}

for(int i = 0; i < 5; i++) {
printf("%d \n", i);
}

printf("tid : %ld, main thread id : %ld\n", tid, pthread_self());

// 主线程调用pthread_join回收子进程资源 - 阻塞进程
int *thread_retval;
ret = pthread_join(tid, (void **)&thread_retval);

/*
解释join为什么传2级指针
int data = 10;
假如你想调用函数修改 data的值一定是 test(&data) 不是test(data)
void test(int a) {}

同理
int **data = 10;
void test(int a) {}
test(** data)
*/

if(ret != 0) {
char *errstr = strerror(ret);
printf("error : %s\n", errstr);
}

printf("exit data : %d\n", *thread_retval);
printf("回收子线程的资源成功\n");

// 让主线程退出
pthread_exit(NULL);
return 0;
}

pthread_detach()线程的分离

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
55
56
57
58
59
60
61
62
/*************************************************************************
> File Name: pthread_detach.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年05月30日 星期一 19时46分59秒
************************************************************************/

/*
* #include <pthread.h>
* int pthread_detach(pthread_t thread);
* - 功能: 分离一个线程,被分离的线程在终止的时候会自动释放资源返回 给系统。
* 1.不能多次的分离,会产生不可预料的行为.
* 2.不能去连接一个已经分离的线程,会报错
* - 参数:需要分离的线程的ID
* - 返回值:
* 成功返回 0
* 失败返回 错误号
*/

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

void *callback(void *arg) {
printf("chid thread id %ld\n", pthread_self());
return NULL;
}

int main() {

// 创建一个子线程
pthread_t tid;
int ret = pthread_create(&tid, NULL, callback, NULL);
if(ret != 0) {
char * errstr = strerror(ret);
printf("error_create : %s\n", errstr);
}

// 输出子线程和子线程ID
printf("tid : %ld, main thread id % ld\n", tid, pthread_self());

// 设置子线程分离,子线程结束时对应的资源就不需要主线程释放
ret = pthread_detach(tid);
if(ret != 0) {
char * errstr = strerror(ret);
printf("error_datach : %s\n", errstr);
}

// 设置线程分离, 对分离的子线程进行链接 pthread_join() - 错误
/*
ret = pthread_join(tid, NULL);
if(ret != 0) {
char * errstr = strerror(ret);
printf("error_join : %s\n", errstr);
}
*/
// 退出主进程
pthread_exit(NULL);

return 0;
}

线程分离之后不能再链接(join)

pthread_cancel() 线程取消

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
55
56
57
/*************************************************************************
> File Name: pthread_cancel.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年05月31日 星期二 09时32分12秒
************************************************************************/

/*
* #include <pthread.h>
* int pthread_cancel(pthread_t thread);
* - 功能: 取消线程(让线程终止)
* 取消某个线程,可以终止某个线程的运行
* 但是并不是立马终止,而是当子线程执行到一个取消点,线程才会终 止
* 取消点:系统规定好的一些系统调用(每个系统都可能不一样),我们可以粗略的理解为 从用户区到内核去的切换这个位置称之为取消点
*
*/


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

void *callback(void *arg) {
printf("chid thread id %ld\n", pthread_self());
for(int i = 0; i < 5; i++) {
printf("child : %d\n", i);
}
return NULL;
}

int main() {

// 创建一个子线程
pthread_t tid;
int ret = pthread_create(&tid, NULL, callback, NULL);
if(ret != 0) {
char * errstr = strerror(ret);
printf("error_create : %s\n", errstr);
}

// 取消线程
pthread_cancel(tid);


for(int i = 0; i < 5; i++) {
printf("%d\n", i);
}

// 输出子线程和子线程ID
printf("tid : %ld, main thread id % ld\n", tid, pthread_self());

// 退出主进程
pthread_exit(NULL);

return 0;
}

线程属性

线程分离 - 获取线程栈的大小

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/*************************************************************************
> File Name: pthread_attr.c
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年05月31日 星期二 13时27分44秒
************************************************************************/

/*

int pthread_attr_init(pthread_attr_t *attr);
- 功能: 初始化线程属性变量

int pthread_attr_destroy(pthread_attr_t *attr);
- 功能: 释放线程属性的资源
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
- 功能: 获取线程分离的状态属性
int pthread_attr_setdetachstate(ptread_attr_t *attr, int detachstate);
- 功能: 设置线程分离的状态属性

*/

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

void *callback(void *arg) {
printf("chid thread id %ld\n", pthread_self());
for(int i = 0; i < 5; i++) {
printf("child : %d\n", i);
}
return NULL;
}

int main() {

// 创建一个线程属性变量
pthread_attr_t attr;
// 初始化属性变量
pthread_attr_init(&attr);

// 设置属性 - PTHREAD_CREATE_DETACHED(线程分离)
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

// 获取线程栈的大小
size_t size;
pthread_attr_getstacksize(&attr, &size);
// printf("thread stack size : %ld\n", size);

// 创建一个子线程 - 设置属性
pthread_t tid;
int ret = pthread_create(&tid, &attr, callback, NULL);
if(ret != 0) {
char * errstr = strerror(ret);
printf("error_create : %s\n", errstr);
}

// 获取线程栈的大小
printf("thread stack size : %ld\n", size);
// 输出子线程和子线程ID
printf("tid : %ld, main thread id % ld\n", tid, pthread_self());


// 释放线程资源
pthread_attr_destroy(&attr);
// 退出主进程
pthread_exit(NULL);

return 0;
}

评论