进程与线程
      典型的UNIX/Linux进程可以看成只有一个控制线程:一个进程在同一时刻只做一件事情。有了多个控制线程后,在程序设计时可以把进程设计成在同一时刻做不止一件事,每个线程各自处理独立的任务。

 进程是程序执行时的一个实例,是担当分配系统资源(CPU时间、内存等)的基本单位。在面向线程设计的系统中,进程本身不是基本运行单位,而是线程的容器。程序本身只是指令、数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行实例。
       “进程——资源分配的最小单位,线程——程序执行的最小单位”
      一个进程至少包含一个线程,进程是运行的程序,程序是静态的概念,进程是动态的概念。
      进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,可以用线程,也可以用进程间的通信。
使用线程的理由
      从上面我们知道了进程与线程的区别,其实这些区别也就是我们使用线程的理由。总的来说就是:进程有独立的地址空间,线程没有单独的地址空间(同一进程内的线程共享进程的地址空间)。

使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。我们知道,在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,总的说来,一个进程的开销大约是一个线程开销的30倍左右,当然,在具体的系统上,这个数据可能会有较大的区别。

使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方。
Linux上线程开发API概要
      多线程开发在 Linux 平台上已经有成熟的 pthread 库支持。其涉及的多线程开发的最基本概念主要包含三点:线程,互斥锁,条件。其中,线程操作又分线程的创建,退出,等待 3 种。互斥锁则包括 4 种操作,分别是创建,销毁,加锁和解锁。条件操作有 5 种操作:创建,销毁,触发,广播和等待。其他的一些线程扩展概念,如信号灯等,都可以通过上面的三个基本元素的基本操作封装出来。详细请见下表:
1、线程创建

#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
// 返回:若成功返回0,否则返回错误编号
//pthread_t是无符号的长整型,第一个参数是pthread_t类型的指针,
//第个二参数是线程的属性
//第三个参数是函数指针
//最后一个参数是给线程传参的一个参数

当pthread_create成功返回时,由tidp指向的内存单元被设置为新创建线程的线程ID。attr参数用于定制各种不同的线程属性,暂可以把它设置为NULL,以创建默认属性的线程。

新创建的线程从start_rtn函数的地址开始运行,该函数只有一个无类型指针参数arg。如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。
线程的退出

单个线程可以通过以下三种方式退出,在不终止整个进程的情况下停止它的控制流:

1)线程只是从启动例程中返回,返回值是线程的退出码。

2)线程可以被同一进程中的其他线程取消。

3)线程调用pthread_exit:
pthread_exit函数

#include <pthread.h>
int pthread_exit(void *rval_ptr);

rval_ptr是一个无类型指针,与传给启动例程的单个参数类似。进程中的其他线程可以通过调用pthread_join函数访问到这个指针。
线程等待

#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
// 返回:若成功返回0,否则返回错误编号

调用这个函数的线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返回或者被取消。如果例程只是从它的启动例程返回i,rval_ptr将包含返回码。如果线程被取消,由rval_ptr指定的内存单元就置为PTHREAD_CANCELED。

可以通过调用pthread_join自动把线程置于分离状态,这样资源就可以恢复。如果线程已经处于分离状态,pthread_join调用就会失败,返回EINVAL。

如果对线程的返回值不感兴趣,可以把rval_ptr置为NULL。在这种情况下,调用pthread_join函数将等待指定的线程终止,但并不获得线程的终止状态。
线程的脱离
一个线程或者是可汇合(joinable,默认值),或者是脱离的(detached)。当一个可汇合的线程终止时,它的线程ID和退出状态将留存到另一个线程对它调用pthread_join。脱离的线程却像守护进程,当它们终止时,所有相关的资源都被释放,我们不能等待它们终止。如果一个线程需要知道另一线程什么时候终止,那就最好保持第二个线程的可汇合状态。

pthread_detach函数把指定的线程转变为脱离状态。

#include <pthread.h>
int pthread_detach(pthread_t thread);
// 返回:若成功返回0,否则返回错误编号

本函数通常由想让自己脱离的线程使用,就如以下语句:

pthread_detach(pthread_self());

线程ID获取及比较

#include <pthread.h>
pthread_t pthread_self(void);
// 返回:调用线程的ID

对于线程ID比较,为了可移植操作,我们不能简单地把线程ID当作整数来处理,因为不同系统对线程ID的定义可能不一样。我们应该要用下边的函数:

#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2);
// 返回:若相等则返回非0值,否则返回0

对于多线程程序来说,我们往往需要对这些多线程进行同步。同步(synchronization)是指在一定的时间内只允许某一个线程访问某个资源。而在此时间内,不允许其它的线程访问该资源。我们可以通过互斥锁(mutex),条件变量(condition variable)和读写锁(reader-writer lock)来同步资源。在这里,我们暂不介绍读写锁。
代码示例

#include<stdio.h>
#include<pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);void*func1(void *arg)
{static int ret=10;//如果不是 static 函数调用结束后 ret 的值会消失static char*p="t1 is run out";printf("t1 :%ld thread is created\n",(unsigned long)pthread_self());printf("t1:param is %d\n",*((int*)arg));pthread_exit((void*)p);
}
int main()
{int ret;int param=100;char *pret;pthread_t t1;ret=pthread_create(&t1,NULL,func1,(void*)&param);if(ret==0){printf("main:create t1 success\n");}printf("main : %ld \n",(unsigned long)pthread_self());pthread_join(t1,(void**)&pret);//这个函数用来等t1线程的退出,他是用在主线程中printf("main:t1 quite return is %s\n",pret);return 0;
}

体现线程共享内存空间代码

{#include<stdio.h>
#include<pthread.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;//主进程和进程1和进程2都共享这一个全局变量
void*func1(void *arg)
{printf("t1 :%ld thread is created\n",(unsigned long)pthread_self());printf("t1:param is %d\n",*((int*)arg));while(1){printf("t1 printf is %d\n",g_data++);sleep(1);}
}void*func2(void *arg)
{printf("t2 :%ld thread is created\n",(unsigned long)pthread_self());printf("t2:param is %d\n",*((int*)arg));while(1){printf("t2 printf is %d\n",g_data++);sleep(1);}
}int main()
{int ret;int param=100;pthread_t t1;pthread_t t2;ret=pthread_create(&t1,NULL,func1,(void*)&param);if(ret==0){printf("main:create t1 success\n");}ret=pthread_create(&t2,NULL,func2,(void*)&param);if(ret==0){printf("main:create t2 success\n");}printf("main : %ld \n",(unsigned long)pthread_self());while(1){printf("main printf is %d\n",g_data++);sleep(1);}pthread_join(t1,NULL);//yong laidengdai t1 xiancheng tuichupthread_join(t2,NULL);//yong laidengdai t1 xiancheng tuichureturn 0;
}
//c此程序三个进程的运行顺序没有确定谁先谁后

Linux上线程开发API概要(线程)相关推荐

  1. C#在Linux上的开发指南

    本人才疏学浅,在此记录自己用C#在Linux上开发的一点经验,写下这篇指南.(给想要在Linux上开发C#程序的朋友提供建议) 目前在Linux上跑的网站:http://douxiubar.com | ...

  2. 在Linux上高效开发的7个建议

    Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发. 我们都知道被困在一段简单代码上数个小时是一个开发者挫败感的由来.出了问题却找不到bug会让人身心俱疲. 我 ...

  3. linux 有线程本地存储 (tls)?,有没有办法确定Linux上的库使用的线程本地存储模型...

    我自己遇到了这个错误,在调查时,我来了一个 mailing list post with this info: If you link a shared object containing IE-mo ...

  4. 这里提供了在Linux上显示某个进程的线程的几种方式

     ps -T top -H

  5. linux上 arm开发环境搭建,详解 LINUX下QT For ARM开发环境搭建过程

    LINUX下QT For ARM开发环境搭建过程是本文介绍的内容,不多说,先来看内容.在PC上,我们需要得到两个版本的Qt,分别是:Qt-4.5.2和QtEmbedded-4.5.2-arm.前者包括 ...

  6. linux上C++开发——1. C++包管理工具

    文章目录 1. 包管理器的作用 1.1 常见的包管理器 1.2 C++使用第三方库的方式 1.3 C++包管理器的诞生 1. 常见的C++包管理工具 1.1 Conan 1.2 vcpkg 1.3 其 ...

  7. linux线程详解:线程概念、线程调度、线程安全、线程模型

    1.线程与进程的区别 (1)线程是轻量级的进程,是程序执行流的最小单位: (2)进程是资源分配的最小单位,线程是调度的最小单位: (3)进程可以创建线程,线程不可以创建进程: (4)一个进程由一个或者 ...

  8. 【Android 逆向】Android 进程注入工具开发 ( 远程进程注入动态库文件操作 | 注入动态库 加载 业务动态库 | 业务动态库启动 | pthread_create 线程开发 )

    文章目录 前言 一.加载 libnattive.so 动态库 二. libnattive.so 动态库启动 三. pthread_create 线程开发 四. 线程执行函数 前言 libbridge. ...

  9. Linux 下查看进程内的线程情况 ps, top 命令

    线程是现代操作系统上进行并行执行的一个流行的编程方面的抽象概念.当一个程序内有多个线程被拆分出用以执行多个流时,这些线程就会在它们之间共享特定的资源(如,内存地址空间.打开的文件),以使拆分开销最小化 ...

最新文章

  1. 养成好的生活和学习习惯
  2. [JS]计算字符串中出现最多的字符和其出现次数
  3. 常见宽带路由器配置及口令清除技巧
  4. Intel Realsense D435 连续验证 摄像头初始化 hardware_reset() 失败案例
  5. python字符串创建_在Python上创建完整的字符串
  6. 操作方法:具有多个Mongo存储库和Kotlin的Spring Boot 2 Web应用程序
  7. 匹配中文字符的正则表达式: [u4e00-u9fa5](
  8. rxjs angular_Angular RxJS深度
  9. [转载] [Python基础语法]关键字、标识符和变量
  10. VAE变分自编码器的一点理解
  11. 膨胀、腐蚀、开、闭运算——数字图像处理中的形态学
  12. 阿里云免费ssl证书更换指南2021.4
  13. 碎片时间都在刷手机?RSSHub带你逃出信息洪流!
  14. 基片集成波导天线设计基础
  15. 做了个抓取全网群二维码和个人二维码的平台
  16. 苹果6plus一直没信号服务器,苹果6sPlus信号弱或者无服务解决方法
  17. 百度网盘加速无限试用_百度网盘临时加速正式上线,最低 2 元
  18. Unity3D开发游戏有没有流行的框架
  19. 亚马逊云科技启示录:创新作帆,云计算的征途是汪洋大海
  20. 【沙龙预告】移动媒体产品新趋势

热门文章

  1. ANSYS 简支梁的约束
  2. 方差和协方差的数据意义
  3. 手机做服务器性能咋样,服务器性能不足 怎样才能逼出最强状态
  4. csgo怎么控制电脑玩家_电脑怎么远程控制他人电脑,教您给电脑设置远程控制的方法...
  5. java的日期操作_java中对时间的操作详解
  6. mysql编译innodb_源码编译MySQL5.1生成InnoDB存储引擎_MySQL
  7. [10] AOP的注解配置
  8. Eclipse is running in a JRE, but a JDK is required 解决方法(转)
  9. android 小工具:pc 上用 curl 命令打开手机浏览器,浏览指定网址
  10. linux查看fcsan设备,fc-san存储