转载出处: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. gitlab ssh 免密登录

    打开本地git   使用 ssh-keygen 工具 输入命令  ssh-keygen -t rsa -C '你的邮箱账号' 接下来输入密码 确认密码 找到目录 找到公钥 在 gitlab 用户设置  ...

  2. Linux vim文件编辑器使用

    学习目标: 通过本实验熟练vim的使用. 步骤: 1.将用户家目录的ls结果重定向到vimfile.txt 2.查看rh124第403页实验要求,并完成 参考命令: 复制文件前,需要先建立文件,教材上 ...

  3. ros3。3教程 入门到高级

    115.com 目录route 基 础 篇(21课) 1 Ros简介 主要讲解ros的基础知识,让用户对ros有个大致了解,并对ros进行简单演示 语音视频 20分16秒   2 CDROM安装 主要 ...

  4. 一、Kubernetes_V1.10集群部署-master-生成证书

    一.证书生成 1.下载cfssl mkdir -p /etc/kubernetes/sslwget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 wget ...

  5. Solrcloud+tomcat+zookeeper

    准备两台服务器,目录结构如下 主机名 IP地址 tomcat安装路径 zookeeper安装路径 solr安装路径 java安装路径 sht-sgmhadoopnn-01 172.16.101.55 ...

  6. 极*Java速成教程 - (1)

    序言 众所周知,程序员需要快速学习新知识,所以就有了<21天精通C++>和<MySQL-从删库到跑路>这样的书籍,Java作为更"高级"的语言也不应该落后, ...

  7. Head First PHP&MySQl第四章代码

    addemail.php <!DOCTYPE html> <html lang="cn" dir="ltr"> <head> ...

  8. 简述在Ubuntu终端打开文件的几种不同方法与区别

    一· 在Ubuntu下,通常用命令行打开文本文件,比如用命令gedit.more.cat.vim.less. gedit:在文本软件下打开文件,可直接修改. more ,cat 和 less :类似, ...

  9. c#EntityFrameworkcodeFirst模式

    一.首先定义数据类 [DataContract(Namespace="http://www.cninnovation.com/Services/2012")]  public cl ...

  10. flume复习(一)

    关于flume官方文档介绍可以去:http://flume.apache.org/看看.接下来就介绍一下关于我个人对flume的理解 一.flume介绍: 1.flume是一个分布式.可靠.和高可用的 ...