Linux - 多线程编程

进程及线程基本定义

进程(process)

处于执行期的程序及其所包含资源的总称

程序:可执行程序代码

资源:打开文件、挂起信号、地址空间、数据段等

线程(thread)

进程中活动的对象

有独立的程序计数器、进程栈及一组进程寄存器

节省主存、减少管理开销、快速切换

进程

资源分配单位

进程的上下文组成

进程控制块PCB:包括进程的编号、状态、优先级以及正文段和数据段中数据分布的大概情况

正文段(text segment):存放该进程的可执行代码

数据段(data segment):存放进程静态产生的数据结构

用户堆栈(stack)

线程

CPU调度基本单位

进程执行状态相关信息

进程 ID、进程组 ID、用户 ID和组 ID
工作环境(Environment)
工作目录(Working directory)
程序指令(Program instructions)
寄存器(Registers)
栈(Stack)
堆(Heap)
文件描述符(File descriptors)
信号(Signal actions )
共享库(Shared libraries)
进程间通信手段(Inter-process communication tools)

线程的基本特点

是进程的一个实体,可作为系统独立调度和分派的基本单位

有不同的状态,有控制线程的各种原语,包括创建和撤销线程等

不拥有系统资源(只拥有从属进程的全部资源,资源是分配给进程)

一个进程中的多个线程可并发执行

进程中创建的线程可执行同一程序的不同部分

也可以执行相同代码

系统开销小、切换快

进程的多个线程都在进程的地址空间活动,共享全局变量

同一进程中的多个线程共享该进程的虚拟空间

进程代码段

进程的公有数据

利用这些共享的数据,线程很容易的实现相互通讯

进程打开的文件描述符

信号的处理器

进程的当前目录和进程用户ID与进程组ID

说明

对不同进程来说,具有独立的数据空间,数据传递只能通过通信的方式进行,这种方式费时而不方便

线程是实现并发的必要条件

线程ID

每个线程都有自己唯一的线程ID

寄存器组的值

创建线程时,须将原有线程的寄存器集合的状态保存

线程的堆栈

线程必须拥有自己的函数堆栈,使得函数调用可以正常执行,不受其他线程的影响

错误返回码

不同线程应该拥有自己的错误返回码变量

线程的信号屏蔽码

线程的信号屏蔽码应由线程自己管理,但所有线程都共享同样的信号处理器

线程的优先级

用户线程

用户线程存在于用户空间,通过线程库来实现

线程库提供对线程的创建、调度和管理的支持,而无须内核支持

内核并不知道用户级线程,所有线程的创建和调度都在用户空间内进行,无须内核干预

用户级线程的调度以进程为单位

优点

同一进程内的线程切换不需要转换到内核,调度算法是进程专用的

缺点

系统调度阻塞问题,不能充分利用多处理器

由操作系统直接支持,内核在其空间内执行线程的创建、调度和管理

由于线程管理由操作系统完成,因此内核线程的创建和管理要慢于用户线程的创建和管理

优点

支持多处理器,支持用户进程中的多线程、内核线程切换的速度快

缺点

对用户的线程切换来说,系统开销大

线程-多线程模型

多对一模型

将许多用户级线程映射到一个内核线程

线程管理在用户空间进行,效率较高

处理机调度的单位仍然是进程

缺点

如果一个线程执行了阻塞系统调用,那么整个进程就会阻塞

因为任何时刻只有一个线程访问内核,多个线程不能并行运行在多处理器上

说明

在不支持内核级线程的操作系统上所实现的用户级线程库也使用多对一模型

一对一模型

将每个用户线程映射到一个内核线程

在一个线程执行阻塞时,允许另一个线程继续执行

允许多个线程运行在多处理机系统上

提供比多对一模型更好的并发功能

缺点

创建一个用户线程就需要创建一个相应内核线程

创建内核线程的开销会影响应用程序的性能,这种模型的绝大多数实现限制系统所支持的线程数量

多对多模型

多路复用许多用户级线程到同样数量或更小数量的内核线程上

内核线程的数量可能与特定应用程序或特定机器有关

克服前两种模型的缺点

开发人员可以创建任意多的必要的线程,并且相应内核线程能在多处理器系统上并行运行

当一个线程执行阻塞系统调用时,内核能调度另一个线程来执行

pthread背景

早期各硬件厂商主要使用私有版本线程库,实现差异非常大,开发者难于开发可移植的线程应用

为能够最大限度的提高线程的性能,需要一个标准的编程接口

对于UNIX系统,IEEE POSIX 1003.1c标准 (1995)定义了这样的接口

遵从该标准实现的线程被称做POSIX线程,或pthreads

pthreads定义了一套C语言编程接口和函数调用

包括一个pthread.h头文件和一个线程库

基于POSIX标准的线程编程接口
包括一个pthread.h头文件和一个线程库
编译方法
gcc  –g  **.c   -o ***  –lpthread
功能
线程管理
支持线程创建/删除、分离/联合,设置/查询线程属性
互斥
处理同步,称为“mutex”
创建/销毁、加锁/解锁互斥量,设置/修改互斥量属性
条件变量
支持基于共享互斥量的线程间通信
建立/销毁、等待/触发特定条件变量,设置/查询条件变量属性
线程管理
支持线程创建、分离、联合等,还包括线程属性的设置/查询
互斥
处理同步,称为“mutex”
提供创建、销毁、加锁和解锁互斥量
也包括补充的修改互斥量属性功能,并用它去设置或者修改与互斥相关的属性
条件变量
支持基于共享互斥量的线程间通信,以开发者的特定条件变量为基础。
包括基于特定条件变量的建立、销毁、等待和信号触发
设置/查询条件变量属性的功能也包括在内

线程管理

线程创建

函数原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void*),void * arg);
参数说明
thread:要创建的线程id指针
attr:创建线程时的线程属性
v(*start_routine)(void*):返回值是void*类型的指针函数
arg:start_routine的参数
返回值
成功返回0
失败返回错误编号
EAGAIN:表示系统限制创建新的线程,如线程数目过多
EINVAL:代表线程属性值非法
#include <pthread.h>

#include <stdio.h>

void *create(void *arg) {
printf("new thread created ..... ");

}

int main(int argc, char *argv[]){
   pthread_t tidp;
   int error;

        error=pthread_create(&tidp, NULL, create, NULL);
     if(error != 0)
      {
         printf("pthread_create is not created ... ");
         return -1;
     }
     printf("prthread_create is created... ");
     return 0;

}
基本问题
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void*),void * arg);
仅允许传递一个参数给线程待执行的函数
如何传递多个参数
解决途径
构造一个包含所有参数的结构,将结构指针作为参数传递给pthread_create()
所有参数必须利用(void *)来传递
获取线程自身的id
函数原型
pthread_t pthread_self(void);
返回值
调用线程的线程id
比较线程ID
函数原型
int pthread_equal(pthread_t tid1, pthread_t  tid2);
参数
tid1:线程1的id
tid2:线程2的id
返回值
相等返回非0值
否则返回0

线程终止

正常终止
方法1:线程自己调用pthread_exit()
void pthread_exit(void *rval_ptr);
rval_ptr:线程退出返回的指针,进程中其他线程可调用pthread_join()访问到该指针
方法2:在线程函数执行return
非正常终止
其它线程的干预
自身运行出错

同步方式(非分离状态)

等待新创建线程结束

只有当pthread_join()函数返回时,创建的线程才算终止,才可释放自己占用的系统资源

异步方式(分离状态)

未被其他线程等待,自己运行结束即可终止线程并释放系统资源

函数原型
int pthread_join( pthread_t thread, void ** rval_ptr);
功能
调用者将挂起并等待新进程终止
当新线程调用pthread_exit()退出或者return时,进程中的其他线程可通过pthread_join()获得进程的退出状态
使用约束
一个新线程仅仅允许一个线程使用该函数等待它终止
被等待线程应处于可join状态,即非DETACHED状态
返回值
成功结束返回值为0,否则为错误编码
说明
类似于waitpid()
函数原型
int pthread_detach(pthread_t thread)
功能
执行该函数后线程处于DETACHED状态
处于该状态的线程结束后自动释放内存资源,不能被pthread_join()同步
说明
当线程被分离时,不能用pthread_join()等待其终止状态
为避免内存泄漏,线程终止要么处于分离状态,要么处于同步状态

功能描述

客户端

使用线程向服务器发送从标准输入得到的字符

在主线程中将从服务器端返回的字符显示到标准输出

服务器端

将客户端发来的数据原样返回给客户端,每一个客户在服务器上对应一个线程

时间: 2024-11-17 01:07:05

Linux - 多线程编程的相关文章

《Linux多线程编程手册》读书笔记

第二章 基本线程编程 1.(P25)如果多个线程等待同一个线程终止,则所有等待线程将一直等到目标线程终止.然后,一个等待线程成功返回,其余的等待线程将失败并返回ESRCH错误. 2.(P26)将新线程的pbe参数作为栈参数进行传递.这个线程参数之所以能够作为栈参数传递,是因为主线程会等待辅助线程终止.不过,首选方法是使用malloc从堆分配存储,而不是传递指向线程栈存储的地址.如果将该参数作为地址传递到线程栈存储,则该地址可能无效或者在线程终止时会被重新分配. 3.(P28)pthread_de

Linux多线程编程-互斥锁

互斥锁 多线程编程中,(多线程编程)可以用互斥锁(也称互斥量)可以用来保护关键代码段,以确保其独占式的访问,这有点像二进制信号量.POSIX互斥锁相关函数主要有以下5个: #include <pthread.h> int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr); int pthread_mutex_destroy(pthread_mutex_t *mutex); int p

Linux多线程编程-条件变量

条件变量 如果说线程间的互斥锁是用来同步共享数据的访问的话,那么条件变量是用于线程之间共享数据的值.条件变量提供了一种线程之间的通知机制,当某个共享数据达到某个值时,唤醒等待这个共享数据的线程.条件变量相关函数主要 有5个: #include <pthread.h> int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr); int pthread_cond_destroy(pthread_

Linux多线程编程初探

Linux 线程介绍 进程与线程 典型的UNIX/Linux进程可以看成只有一个控制线程:一个进程在同一时刻只做一件事情.有了多个控制线程后,在程序设计时可以把进程设计成在同一时刻做不止一件事,每个线程各自处理独立的任务. 进程是程序执行时的一个实例,是担当分配系统资源(CPU时间.内存等)的基本单位.在面向线程设计的系统中,进程本身不是基本运行单位,而是线程的容器.程序本身只是指令.数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行实例. 线程是操作系统能够进行运算调度的最小单位

Linux多线程编程小结

 Linux多线程编程小结 前一段时间由于开题的事情一直耽搁了我搞Linux的进度,搞的我之前学的东西都遗忘了,非常烦躁的说,如今抽个时间把之前所学的做个小节.文章内容主要总结于<Linux程序设计第3版>. 1.Linux进程与线程 Linux进程创建一个新线程时,线程将拥有自己的栈(由于线程有自己的局部变量),但与它的创建者共享全局变量.文件描写叙述符.信号句柄和当前文件夹状态. Linux通过fork创建子进程与创建线程之间是有差别的:fork创建出该进程的一份拷贝,这个新进程拥有自己的

Linux多线程编程和Linux 2.6下的NPTL

Linux多线程编程和Linux 2.6下的NPTL 在Linux 上,从内核角度而言,基本没有什么线程和进程的区别--大家都是进程.一个进程的多个线程只是多个特殊的进程他们虽然有各自的进程描述结构,却共享了同一 个代码上下文.在Linux上,这样的进程称为轻量级进程Light weight process.致此,就是关于线程的总体概念了,我们往往就在了解这个概念的情况下开始我们的多线程编程之旅.这对于多线程编程入门已经足够了,然而事 实上线程却要复杂的多. 首先多线程间的优先级调度,内存资源(

Linux多线程编程详解 [By: HarryAlex]

本文内容主要参考于<Linux程序设计·第3版>.<Linux环境C程序设计>.<C语言核心技术>.<深入理解计算机系统·第2版>,代码运行环境: Linux version 3.10.0-123.el7.x86_64 ([email protected]) (gcc version 4.8.2 20140120 (Red Hat 4.8.2-16) (GCC) ) #1 SMP Thu Jun 4 17:17:49 CST 2015 1. Linux进程与

Linux——多线程编程

#include<pthread.h>linux 多线程编程: pthread_t 线程名 pthread_create(pthread * thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);) 创建线程 pthread_exit(void *retval) 结束线程 retval存放线程退出状态 pthread_join(pthread_t thread, void** retval)

Linux多线程编程

——本文一个例子展开,介绍Linux下面线程的操作.多线程的同步和互斥. 前言 线程?为什么有了进程还需要线程呢,他们有什么区别?使用线程有什么优势呢?还有多线程编程的一些细节问题,如线程之间怎样同步.互斥,这些东西将在本文中介绍.下面是一道面试题: 是否熟悉POSIX多线程编程技术?如熟悉,编写程序完成如下功能: 1)有一int型全局变量g_Flag初始值为0: 2) 在主线称中起动线程1,打印“this is thread1”,并将g_Flag设置为1 3) 在主线称中启动线程2,打印“th

Linux多线程编程-信号量

在Linux中,信号量API有两组,一组是多进程编程中的System V IPC信号量:另外一组是我们要讨论的POSIX信号量.这两组接口类似,但不保证互换.POSIX信号量函数都已sem_开头,并不像大多数线程函数那样以pthread_开头,常用的有以下5个: #include <semaphore.h> int sem_init(sem_t* sem, int pshared, unsigned int value); int sem_destroy(sem_t *sem); int se