转载出处:https://blog.csdn.net/skyroben/article/details/72793409

1.背景知识

Linux没有真正意义上的线程,它的实现是由进程来模拟,所以属于用户级线程,位于libpthread共享库(所以线程的ID只在库中有效),遵循POSIX标准。

Windows下有一个真正的数据结构TCB来描述线程。

Linux上两个最有名的线程库LinuxThreads和NPTL。

Linux两个线程模型的比较:

Linux线程模型的比较

Linux下多线程虚拟地址空间的映射类似于用vfork创建多个子进程。

2.进程和线程的区别

进程:程序的一个动态运行实例,承担分配系统资源的实例。(Linux实现进程的主要目的是资源独占)

线程:在进程的内部运行(进程的地址空间)运行的一个分支,也是调度的基本单位(调度按LWP调度)。(Linux实现线程的主要目的是资源共享)

线程所有的资源由进程提供。

单进程:只有一个进程的线程(LWP=PID)。

LWP:轻量级进程。

由于同一进程的多个线程共享同一地址空间,因 此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:

1. 文件描述符表
2. 每种信号的处理方式(SIG_IGN、SIG_DFL或者自定义的信号处理函数)  
3. 当前工作目录
4. 用户id和组id
但有些资源是每个线程各有一份的:
1.线程ID
2. 上下文信息,包括各种寄存器的值、程序计数器和栈指针
3. 栈空间
4. errno变量
5. 信号屏蔽字
6. 调度优先级

多线程程序的优点(相对进程比较而言):

1. 多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间,创建销毁速度快。
2.是线程间方便的通信机制。由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。

3.进程控制

在Linux系统下,与线程相关的函数都定义在pthread.h头文件中。

创建线程函数———pthread_create函数

  1. #include <pthread.h>
  2. int pthread_create(pthread_t * thread, const pthread_arrt_t* attr,void*(*start_routine)(void *), void* arg);

(1)thread参数是新线程的标识符,为一个整型。

(2)attr参数用于设置新线程的属性。给传递NULL表示设置为默认线程属性。
(3)start_routine和arg参数分别指定新线程将运行的函数和参数。start_routine返回时,这个线程就退出了
(4)返回值:成功返回0,失败返回错误号。
        线程id的类型是thread_t,它只在当前进程中保证是唯一的,在不同的系统中thread_t这个类型有不同的实现,调用pthread_self()可以获得当前线程的id
        进程id的类型时pid_t,每个进程的id在整个系统中是唯一的,调用getpid()可以获得当前进程的id,是一个正整数值。

终止线程———pthread_cancel函数和pthread_exit函数

终止某个线程而不终止整个进程,可以有三种方法:
1. 从线程函数return。这种方法对主线程不适应,从main函数return相当于调用exit。
2. 一个线程可以调用pthread_cancel终止同一进程中的另一个线程。
3. 线程可以调用pthread_exit终止自己。
  1. #include <pthread.h>
  2. int pthread_cancel(pthread_t thread);
(1)thread参数是目标线程的标识符。
(2)该函数成功返回0,失败返回错误码。
  1. #include <pthread.h>
  2. void pthread_exit(void * retval);
(1)retval是void *类型,其它线程可以调用pthread_join获得这个指针。需要注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是由malloc分 配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。

(2)pthread_exit函数通过retval参数向线程的回收者传递其退出信息。它执行之后不会返回到调用者,且永远不会失败。

线程等待———pthread_join

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

(1)调用该函数的线程将挂起等待,直到id为thread的线程终止。

(2)thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,
总结如下:
1. 如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值。
2. 如果thread线程被别的线程调用pthread_cancel异常终掉,value_ptr所指向的单元里存放的是常数PTHREAD_CANCELED。
3. 如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。 如果对thread线程的终止状态不感兴趣,可以传NULL给value_ptr参数。
(3)成功返回0,失败返回错误码。可能出现的错误码:

4.分离线程

1.在任何一个时间点上,线程是可结合的(joinable)或者是分离的(detached)。
2.一个可结合的线程能够被其他线程收回其资源和杀死。在被其他线程回收之前,它的存储器资源
(例如栈)是不释放的。(默认情况下线程的创建都是可结合的)
3.一个分离的线程是不能被其他线程回收或杀死的,它的存储器 资源在它终止时由系统自动释放。

4. 如果一个可结合线程结束运行但没有被join,会导致部分资源没有被回收,所以创建线程者应该调用pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源。

调用pthread_join后,如果该线程没有运行结束,调用者会被阻塞。如何解决这种情况呢?
例如,在Web服务器中当主线程为每个新来的连接请求创建一个子线程进行处理的时候,主线程并不希望因为调用pthread_join而阻塞(因为还要继续处理之后到来的连接请求),这时可以在子线程中加入代码 pthread_detach(pthread_self())或者父线程调用pthread_detach(thread_id)(非阻塞,可立即返回)这将该子线程的状态设置为分离的(detached),如此一来,该线程运行结束后会自动释放所有资源。
验证代码:
  1. #include <stdio.h>
  2. #include <error.h>
  3. #include <stdlib.h>
  4. #include <pthread.h>
  5. void* thread_run(void* _val)
  6. {
  7. pthread_detach(pthread_self()); //注释这句代码join success
  8. printf("%s\n", (char*)_val);
  9. return NULL;
  10. }
  11. int main()
  12. {
  13. pthread_t tid;
  14. int tret = pthread_create(&tid, NULL, thread_run, "thread_run~~~~~");
  15. //线程创建成功之后,程序的执行流变成两个,一个执行函数thread_run,一个继续向下执行。
  16. if (tret == 0)
  17. {
  18. sleep(1);
  19. int ret = pthread_join(tid, NULL);
  20. if (ret == 0)
  21. {
  22. printf("pthread_join success\n");
  23. return ret;
  24. }
  25. else
  26. {
  27. printf("pthread_join failed info: %s\n", strerror(ret));
  28. return ret;
  29. }
  30. }
  31. else
  32. {
  33. printf("create pthread failed info: %s", strerror(tret));
  34. return tret;
  35. }
  36. }

运行结果:

分析:
可以看到被分离的线程不可以被等待;一个线程初始为可结合的,要么在父线程等待或分离,要么在子线程分离,只能采取上述几种措施的一种。

Linux多线程编程之pthread相关推荐

  1. Linux多线程编程之pthread (多线程编程) --- (高级)---原作优秀

    https://blog.csdn.net/skyroben/article/details/72793409 (博客优秀) 1.背景知识 Linux没有真正意义上的线程,它的实现是由进程来模拟,所以 ...

  2. 多线程编程之Linux环境下的多线程(三)——好文

    http://www.cnblogs.com/kuliuheng/p/4063892.html 前面两篇文章都讲述了Linux环境下的多线程编程基础知识,也附带了典型实例.本文主要比较一下Linux环 ...

  3. linux c编程之fcntl

    fcntl可实现对指定文件描述符的各种操作,其函数原型如下: int fcntl(int fd, int cmd, ... /* arg */ ); 其中,操作类型由cmd决定.cmd可取如下值: F ...

  4. python 多线程编程之_thread模块

    python 多线程编程之_thread模块 参考书籍:python核心编程 _thread模块除了可以派生线程外,还提供了基本的同步数据结构,又称为锁对象(lock object,也叫原语锁.简单锁 ...

  5. linux C编程之makefile

    linux C编程之makefile 目的:       基本掌握了 make 的用法,能在Linux系统上编程. 环境:       Linux系统,或者有一台Linux服务器,通过终端连接.一句话 ...

  6. Linux网络编程之IP地址转换为无符号整数的方法

    Linux网络编程之IP地址转换为无符号整数的方法,代码如下:(没考虑异常输入) #include <stdio.h> #include <string.h> #include ...

  7. iOS多线程编程之NSThread的使用(★★★推荐,为原作者点赞★★★)

    文章来源:http://blog.csdn.net/totogo2010/article/details/8010231 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThre ...

  8. Linux网络编程之sockaddr与sockaddr_in,sockaddr_un结构体详细讲解

    Linux网络编程之sockaddr与sockaddr_in,sockaddr_un结构体详细讲解 (1)sockaddr struct sockaddr { unsigned  short  sa_ ...

  9. [Cocoa]深入浅出Cocoa多线程编程之 block 与 dispatch quene

    深入浅出 Cocoa 多线程编程之 block 与 dispatch quene 罗朝辉(http://www.cppblog.com/kesalin CC 许可,转载请注明出处 block 是 Ap ...

  10. linux读取文件修改时间函数,Linux服务器编程之utime()函数修改文件存取时间

    Linux服务器编程之utime()函数修改文件存取时间 C语言utime()函数:修改文件的存取时间和更改时间 头文件: #include #include 定义函数: int utime(cons ...

最新文章

  1. 普通二叉树、二叉查找树、平衡二叉树常见操作汇总
  2. 赫夫曼树(哈夫曼树)
  3. 2、ALTER TABLE:修改数据表
  4. 计算机网络实验做什么的,计算机网络实验,做网线.ppt
  5. 华为笔记本软件商店_华为应用市场 PC 端体验:干净好用 - 华为
  6. java 网络编程 方式_JAVA网络编程
  7. java的课后作业咋写_写的简单的java第三季的课后作业
  8. 详解 Qt 串口通信程序全程图文 (4)
  9. linux进程作为服务,将一个监视进程做成linux系统服务
  10. 神秘组织正在运行数百个恶意 Tor 中继
  11. python 写文件 编码_Python文件写入时的编码问题解决
  12. PAT甲级1002 多项式相加
  13. Erlang进程堆垃圾回收机制
  14. matlab混合copula,​MATLAB实战—最优Copula函数的选择
  15. 10分钟搞定工作周报
  16. protoc执行命令
  17. 服务器后台自动运行程序和停止
  18. 提高软件CPU占用率
  19. 服务器客户端证书,客户端如何验证HTTPS服务端证书信息
  20. idea回退操作reset、revert

热门文章

  1. w3school和w3cschool两个网站有什么关系和区别?
  2. 中文文本校对源码java_文字校对应该怎么校对?
  3. 认识AutoCAD 2022 –互联设计体验
  4. 物流 计算机管理 好处,物流配送管理系统的好处与可行性分析
  5. 搭建MySQL可视化Web界面服务器
  6. 【交换机在江湖】第十二章 VLAN基础篇
  7. 文件服务器 共享 端口,共享文件服务端口设置
  8. ShowModalDialog数据缓存的清除方法
  9. 区块链隐私保护:技术和相关项目
  10. linux内核符号地址,Linux内核-模块专用地址空间