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

一、背景知识

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

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

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

Linux两个线程模型的比较:

Linux线程模型的比较

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

二、进程和线程的区别

进程:程序的一个动态运行实例,承担分配系统资源的实例。(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.是线程间方便的通信机制。由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。
 

三、进程控制

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

创建线程函数——pthread_create函数

#include <pthread.h>
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终止自己。
 
#include <pthread.h>

int pthread_cancel(pthread_t thread);
(1)thread参数是目标线程的标识符。
(2)该函数成功返回0,失败返回错误码。
#include <pthread.h>

void pthread_exit(void * retval);
(1)retval是void *类型,其它线程可以调用pthread_join获得这个指针。需要注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是由malloc分 配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。

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

 

线程等待——pthread_join

#include <pthread.h>

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,失败返回错误码。可能出现的错误码:
 

四、分离线程

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

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

      
调用pthread_join后,如果该线程没有运行结束,调用者会被阻塞。如何解决这种情况呢?      
    例如,在Web服务器中当主线程为每个新来的连接请求创建一个子线程进行处理的时候,主线程并不希望因为调用pthread_join而阻塞(因为还要继续处理之后到来的连接请求),这时可以在子线程中加入代码 pthread_detach(pthread_self())或者父线程调用pthread_detach(thread_id)(非阻塞,可立即返回)这将该子线程的状态设置为分离的(detached),如此一来,该线程运行结束后会自动释放所有资源。
 
验证代码:
#include <stdio.h>
#include <error.h>
#include <stdlib.h>
#include <pthread.h> void* thread_run(void* _val)
{
pthread_detach(pthread_self()); //注释这句代码join success
printf("%s\n", (char*)_val);
return NULL;
} int main(){
pthread_t tid;
int tret = pthread_create(&tid, NULL, thread_run, "thread_run~~~~~");
//线程创建成功之后,程序的执行流变成两个,一个执行函数thread_run,一个继续向下执行。
if (tret == ){
sleep();
int ret = pthread_join(tid, NULL);
if (ret == ){
printf("pthread_join success\n");
return ret;
}else{
printf("pthread_join failed info: %s\n", strerror(ret));
return ret;
}
}else{
printf("create pthread failed info: %s", strerror(tret));
return tret;
}
}
运行结果:
分析:
可以看到被分离的线程不可以被等待;一个线程初始为可结合的,要么在父线程等待或分离,要么在子线程分离,只能采取上述几种措施的一种。

[转] Linux多线程编程之pthread的更多相关文章

  1. [转]c++多线程编程之pthread线程深入理解

    多线程编程之pthread线程深入理解         Pthread是 POSIX threads 的简称,是POSIX的线程标准.           前几篇博客已经能给你初步的多线程概念.在进一 ...

  2. 多线程编程之pthread线程深入理解

    不同的平台和操作系统上 进程和线程的实现机制不完全一致  但是一般来说线程栈都是独立的 只要得到地址就可以相互访问       Pthread是 POSIX threads 的简称,是POSIX的线程 ...

  3. Linux应用编程之lseek详解

    Linux应用编程之lseek详解 1.lseek函数介绍 (1).文件指针:当我们要对一个文件进行读写时,一定要先打开这个文件,所以我们读写的所有文件都是动态文件.动态文件在内存中的形态就是文件流的 ...

  4. iOS多线程编程之NSThread的使用

      目录(?)[-] 简介 iOS有三种多线程编程的技术分别是 三种方式的有缺点介绍 NSThread的使用 NSThread 有两种直接创建方式 参数的意义 PS不显式创建线程的方法 下载图片的例子 ...

  5. iOS多线程编程之NSThread的使用(转)

    本文由http://blog.csdn.net/totogo2010/原创 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation  ...

  6. [转] iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

    介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ...

  7. [转] iOS多线程编程之NSOperation和NSOperationQueue的使用

    <iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是用定义好 ...

  8. [转]iOS多线程编程之NSThread的使用

    1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue ...

  9. iOS 多线程编程之Grand Central Dispatch(GCD)

    介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的. 它 ...

随机推荐

  1. jqueryweui关于switch css与js结合

    .invoice_wrapper{ .comm_con{ .weui-switch-cp{ .weui-switch-cp__box{ height:0.4rem; margin:0.25rem 0; ...

  2. DVWA、 DSVM 环境搭建简述

    DVWA(http://www.dvwa.co.uk/)是一个本地的漏洞演示环境基于PHP和Mysql . 另外还有基于Python的DSVM部署起来也十分简单.(https://github.com ...

  3. HDU 1069 Monkey and Banana (动态规划、上升子序列最大和)

    Monkey and Banana Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  4. Luogu P1080 [NOIP2012]国王游戏

    题目 按\(a_i*b_i\)升序排序即可. 证明考虑交换法. 对于排序后相邻的两个人\(i,j(a_ib_i\le a_jb_j)\),设前面的总的积为\(s\),则当前答案为\(\max(\fra ...

  5. POJ 2528 ——Mayor's posters(线段树+区间操作)

    Time limit 1000 ms Memory limit 65536 kB Description The citizens of Bytetown, AB, could not stand t ...

  6. phpstorm配置phpunit进行单元测试

    1.配置单元测试目录: (1)autoload.php <?php function autoloader($dir){ spl_autoload_register(function($name ...

  7. wex5 如何在js中给data添加数据

    var options = { defaultValues :[ {'xuetang' : xuetang,'time' : time} ] }; this.comp("xuetangDat ...

  8. phpstudy mysql数据连接不上(#1130)解决办法

    问题:无论输什么密码,都显示#1130,找半天在终于在百度知道找到了,其他帖子都是水贴,暂时不知道为什么要这么加,反正加了重置服务就好了,重新打开phpMyAdmin 输入默认密码root既可 解决办 ...

  9. 3-关于ES的几个小疑问和解答

    1.ES如何实现分布式 2.ES如何实现高实时 3.ES如何实现高扩展 4.ES7.x版本为何废弃type 5.搜索原理--知乎es

  10. php邮件防注入以及实现经典代码

    <?php function spamcheck($field) {     // filter_var() 过滤 e-mail     // 使用 FILTER_SANITIZE_EMAIL ...