Linux系统应用编程 --- 线程原语

简介: Linux系统应用编程 --- 线程原语

1. pthread_create

1. #include <pthread.h>
2. 
3. int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
4. 
5. 
6. pthread_t *thread:传递一个pthread_t变量地址进来,用于保存新线程的tid(线程ID)
7. 
8. const pthread_attr_t *attr:线程属性设置,如使用默认属性,则传NULL
9. 
10. void *(*start_routine) (void *):函数指针,指向新线程应该加载执行的函数模块
11. 
12. void *arg:指定线程将要加载调用的那个函数的参数

返回值:成功返回0,失败返回错误号。以前学过的系统函数都是成功返回0,失败返回-1,而错误号保存在全局变量errno中,而pthread库的函数都是通过返回值返回错误号,虽然每个线程也都有一个errno,但这是为了兼容其它函数接口而提供的,pthread库本身并不使用它,通过返回值返回错误码更加清晰。

在一个线程中调用pthread_create()创建新的线程后,当前线程从pthread_create()返回继续往下执行,而新的线程所执行的代码由我们传给pthread_create的函数指针start_routine决定。

2. pthread_self

1. #include <pthread.h>
2. 
3. pthread_t pthread_self(void);

获取调用线程tid,其作用对应进程中getpid()函数。

线程ID:pthread_t类型,其本质是在Linux下是无符号整数,其他系统中可能是结构体实现

线程ID是进程内部识别标志。(两个进程间,线程ID允许相同)

注意:不应该使用全局变量pthread_t tid,在子进程中通过pthread_create传出参数来获取线程ID,而应该使用pthread_self()

 

线程ID与线程号的区别:

Ps –eLf命令看到的LWP那一列是线程号,线程号是CPU分配时间轮片的依据

Pthread_self得到的是线程ID,线程ID用来在进程内部区分线程

 

程序1:循坏创建多个子线程

1. #include <stdio.h>
2. #include <string.h>
3. #include <unistd.h>
4. #include <stdlib.h>
5. #include <pthread.h>
6. 
7. void *thread_func(void *arg)
8. {
9.  int i = (int )arg;
10.   sleep(i);
11.   printf("%dth thread: thread id = %lu, pid = %u\n", i+1, pthread_self(), getpid());
12. 
13.   return NULL;
14. }
15. 
16. int  main(void)
17. {
18.   pthread_t tid;
19.   int ret, i;
20. 
21.   for(i=0; i<5; i++){
22.     ret = pthread_create(&tid, NULL, thread_func, (void *)i);
23.     if(ret != 0){
24.       fprintf(stderr, "pthread_create error:%s\n", strerror(ret));
25.       exit(1);
26.     }
27.   }
28. 
29.   //sleep(i);
30. 
31.   //return 0;     //将当前进程退出
32.   pthread_exit(NULL);
33. 
34. }

执行结果如下:

线程默认共享数据段、代码段等地址空间,常用的是全局变量,而进程不共享全局变量,只能借助mmap.

 

程序2:验证线程之间共享全局数据

1. #include <stdio.h>
2. #include <string.h>
3. #include <unistd.h>
4. #include <stdlib.h>
5. #include <pthread.h>
6. 
7. int var = 100;
8. 
9. void *tfn(void *arg)
10. {
11.   var = 200;
12.   printf("thread.\n");
13. 
14.   return NULL;
15. }
16. 
17. int  main(void)
18. {
19.   printf("At first var = %d.\n", var);
20. 
21.   pthread_t tid;
22.   pthread_create(&tid, NULL, tfn, NULL);
23.   sleep(1);
24. 
25.   printf("after pthread_create, var = %d.\n", var);
26. 
27.   return 0;     //将当前进程退出
28. 
29. }

执行结果如下:

主控线程先结束,其他子线程也不会在执行 。如果任意一个线程调用了exit或_exit,则整个进程的所有线程都终止。

3. pthread_exit

1. #include <pthread.h>
2. 
3. void pthread_exit(void *retval);

void *retval:线程退出时传递出的参数,可以是退出值或地址,如是地址时,不能是线程内部申请的局部地址。一般传NULL。

pthread_exit与exit的区别:

调用线程退出函数pthread_exit,只是推出当前线程

任何线程里使用exit都会导致进程退出,主控线程退出时不能return或exit,因为会影响其他线程未工作。

 

exit与_exit的区别:

exit关闭C标准文件流,并刷新文件缓冲区

_exit(Linux底层函数),导致进程退出,关闭未关闭的文件描述符

 

需要注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。

 

4. pthread_join

阻塞等待线程退出,获取线程退出状态,其作用对应进程中的waitpid()函数

1. #include <pthread.h>
2. 
3. int pthread_join(pthread_t thread, void **retval);

pthread_t thread:回收线程的tid

void **retval:接收退出线程传递出的返回值

返回值:成功返回0,失败返回错误号

回收一个线程,获得线程退出值,如果线程没有终止,阻塞等待线程退出

5. pthread_cancel

在进程内的某个线程可以取消另一个线程

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

 

来一段code熟悉下刚才的API

1. #include <stdio.h>
2. #include <stdlib.h>
3. #include <pthread.h>
4. #include <unistd.h>
5. 
6. void *thr_fn1(void *arg)
7. {
8.  printf("thread 1 returing\n");
9.  return (void *) 1;
10. }
11. 
12. void *thr_fn2(void * arg)
13. {
14.   printf("thread 2 exiting\n");
15.   pthread_exit((void * )2);
16. }
17. 
18. 
19. void *thr_fn3(void * arg)
20. {
21.   while(1)
22.   {
23.     printf("thread3 writing\n");
24.     sleep(1);
25.   }
26. }
27. 
28. int main(void)
29. {
30.   pthread_t tid;
31.   void * tret;
32. 
33.   pthread_create(&tid, NULL, thr_fn1, NULL);
34.   pthread_join(tid, &tret);
35.   printf("thread 1 exit code %d\n", (int )tret);
36. 
37.   pthread_create(&tid, NULL, thr_fn2, NULL);
38.   pthread_join(tid, &tret);
39.   printf("thread 2 exit code %d\n", (int )tret);
40. 
41.   pthread_create(&tid, NULL, thr_fn3, NULL);
42.   sleep(3);
43.   pthread_cancel(tid);
44.   pthread_join(tid, &tret);
45. 
46.   return 0;
47. }

执行结果如下:

 

6. pthread_detach

1. #include <pthread.h>
2. 
3. int pthread_detach(pthread_t tid);

pthread_t tid:分离线程tid

返回值:成功返回0,失败返回错误号。

 

一般情况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL。如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。

7. pthread_equal

比较两个线程是否相等

 

线程终止方式

如果需要只终止某个线程而不终止整个进程,可以有三种方法:

1.从线程主函数return。这种方法对主控线程不适用,从main函数return相当于调用exit。

2.一个线程可以调用pthread_cancel终止同一进程中的另一个线程。

3.线程可以调用pthread_exit终止自己

相关文章
|
3天前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
18 3
|
3天前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
15 2
|
3天前
|
安全 网络协议 Linux
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。通过掌握 ping 命令,读者可以轻松测试网络连通性、诊断网络问题并提升网络管理能力。
18 3
|
6天前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
23 6
|
6天前
|
Linux
在 Linux 系统中,`find` 命令是一个强大的文件查找工具
在 Linux 系统中,`find` 命令是一个强大的文件查找工具。本文详细介绍了 `find` 命令的基本语法、常用选项和具体应用示例,帮助用户快速掌握如何根据文件名、类型、大小、修改时间等条件查找文件,并展示了如何结合逻辑运算符、正则表达式和排除特定目录等高级用法。
30 6
|
7天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
4天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
7天前
|
监控 网络协议 算法
Linux内核优化:提升系统性能与稳定性的策略####
本文深入探讨了Linux操作系统内核的优化策略,旨在通过一系列技术手段和最佳实践,显著提升系统的性能、响应速度及稳定性。文章首先概述了Linux内核的核心组件及其在系统中的作用,随后详细阐述了内存管理、进程调度、文件系统优化、网络栈调整及并发控制等关键领域的优化方法。通过实际案例分析,展示了这些优化措施如何有效减少延迟、提高吞吐量,并增强系统的整体健壮性。最终,文章强调了持续监控、定期更新及合理配置对于维持Linux系统长期高效运行的重要性。 ####
|
6月前
|
缓存 Linux 测试技术
安装【银河麒麟V10】linux系统--并挂载镜像
安装【银河麒麟V10】linux系统--并挂载镜像
1664 0
|
6月前
|
关系型数据库 MySQL Linux
卸载、下载、安装mysql(Linux系统centos7)
卸载、下载、安装mysql(Linux系统centos7)
231 0