线程:
1>在一个程序里的一个执行路线叫做线程,线程是一个进程内部的控制序列
2>一个进程至少都有一个执行线程
线程和进程创建过程简单图示:
线程和进程:
1.进程:程序的一次执行过程
在Linux操作系统中,系统维护了一块PCB用来描述进程,从PCB中我们可以看出来:
进程标识;
进程的代码和数据(内存指针:进程中指针指向);
进程调度;
进程状态;
进程的上下文,进程的记账信息(统计进程在CPU上执行的时间等信息;多上行语句);
文件描述符表;
描述信号和进程之间的关系;
2.线程:
1.操作系统运算调度的基本单位;
2.线程被包含在进程中,是进程中实际运作单位;
3.一条线程是进程中的一个单一顺序的控制流;
4.一个进程可以并发多个线程,每条线程并行执行不同的任务;
进程:(资源的管理和分配)
1.资源所有权:内存(虚拟地址空间)、文件、IO设备、操作系统执行保护功能防止进程间发生不必要的资源相关冲突
2.调度/执行:沿着一个或多个程序的执行路径执行;具有执行状态和优先级,是被操作系统调度和分派的实体
进程(线程组/任务):是资源竞争(分配)的基本单位
线程(Linux -- 轻量级进程(LWP)):是程序执行的最小单位
一个进程内的全部进程共享同一个全局内存空间,这使得进程间很容易共享信息,但是这种容易性也带来可同步问题。一个进程内的线程不光共享全局变量,以下信息也是它们所共享的:
1.进程指令
2.同一地址空间,即Text Segment、Data Segment都是共享的,如果定义一个函数在各个线程中都可以调用,如果定义一个全局变量,在各个线程中都可以访问。
3.打开的文件(文件描述符表)
4.每种信号的处理方式
5.当前工作目录
6.用户id和组id
每个线程也有自己独立的信息:
1.线程ID
2.寄存器集合,包括程序计数器和栈指针
3.栈 (用于存放局部变量和返回地址)
4.errno
5.信号屏蔽字
6.调度优先级
线程的优点:
1>创建一个新线程的代价要比创建一个新进程小的多 1/5
2>与进程间的切换相比,线程之间的切换需要操作系统做的工作要少的多
3>线程占用的资源要比进程少很多
4>能充分利用多处理器的并行数量
5>在等待慢速的I/O操作结束的同时,程序可执行其他的计算机任务
6>计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
7>I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作
线程缺点:
1>编码、调试难度提高
2>缺乏访问控制,一个线程崩溃,会导致整个程序都异常终止,一个线程中调用某些函数(signal/kill/exit)会影响整个进程
POSIX线程库:
与线程有关的函数构成了一个完整的系列,绝大多数的名字都是以“pthead_”开头的
连接着写函数库时要使用编译器命令的“_lpthread” 选项。
进程和线程的操作函数对比:
线程创建:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
thread :新线程的标识符
attr:用于设置线程属性,一般置NULL, sart_routine和arg参数分别指定新线程运行的函数及其参数。
返回值: 成功返回0,错误返回错误码。
线程退出:
1>线程只是从启动例程中返回,返回值是线程的退出码。
2>线程可以被同一进程中的其他线程取消(pthread_cancle())。
3>线程调用pthread_exit().
void pthread_exit(void *retval);
函数执行完之后不回到调用者,且退出函数不会失败。
线程等待:调用线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返回或被取消。
为什么要进行线程等待?
1.线程的入口函数有返回结果,有时候会用到这个结果;
2.这个结果在线程退出时一直在内存中保存,直到有其他线程来读取,才会释放 ;
3.否则会产生类似于僵尸进程的场景,创建新的线程不会复用刚才退出线程的地址空间;
int pthread_join(pthread_t thread, void **retval); //retval一般置为NULL
返回值:成功返回0,失败返回错误码。
线程的取消:cancel后线程不会立即退出,而是等到取消点。---------- 取消点:凡是系统调用的位置都是取消点
int pthread_cancel(pthread_t thread);
返回值:成功返回0,失败返回错误编号。
void pthread_testcancel(void); 人为设置取消点
获取线程ID:
pthread_t pthread_self(void);
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/syscall.h>
void* func(void* arg)
{
// while(1)
// {
// printf("this is func thread\n");
// sleep(1);
// }
while(1)
printf("this is thread one %X %d\n", pthread_self(),
syscall(SYS_gettid));
sleep(2);
}
int main()
{
pthread_t tid;
int ret = pthread_create(&tid, NULL, func, NULL);
if(0 != ret)
{
fprintf(stderr, "create : %s\n", strerror(errno));
exit(0);
}
// while(1)
// {
// printf("this is main thread\n");
// sleep(1);
// }
pthread_join(tid, NULL);
}
gdb调试线程简单步骤:
1.gdp attach + 进程ID;
2.info thread;
3.thread i 切换线程
4.bt查看调用栈
5.* --当前线程