进程与线程
进程
进程
是包含程序指令和相关资源的集合,每个进程和其他进程一起参与调度,竞争 C P U CPU CPU、内存等系统资源。- 每个
进程
都有一个非负整型表示的唯一进程 I D ID ID 进程
是系统资源进行资源分配和调度的一个独立的单位
线程
- “轻量级进程”,是一个基本的 C P U CPU CPU执行单元,也是程序执行流的最小单元
线程
只是进程中的一个实体,是系统独立调度的单元,线程本身不拥有系统资源,但是它可以与同属一个进程的其他线程共享进程所属的全部系统资源
引入多线程
-
进程
的引入可以解决多用户支持的问题,但进程
的频繁切换引起的额外开销可能会严重影响系统性能,这个时候就引入了线程
的概念。 -
通过
线程
可以支持同一个应用程序内部的并发,免去了进程频繁切换的开销,另外并发任务间通信也更简单。 -
网路程序具有天生的并发性,比如网络数据库可能需要同时处理数以千计的请求。而由于网络连接的时延具有不确定性和不可靠性,一旦等待一次网络交互时,可以让
当前线程
进入睡眠,退出调度,而去处理其他线程
,这样能够有效利用系统资源,充分发挥系统实时处理能力。 -
线程
的切换也是轻量级的,所有可以保证足够快。每当有事件发生状态改变,都能有线程
及时响应,而且每次线程内部处理的计算强度和复杂度都不大。在这种情况下,多线程
实现的模型也是高效的。
多线程简单理解
-
我们都知道,一般一个程序的运行过程中,只有一个控制权的存在。当函数被调用时,该函数获得控制权,即称为激活函数
-
而多线程就是允许一个进程存在多个控制权,以便让多个函数同时处于激活状态
- 上图左边即为单线程程序;右图中 m a i n − − > f u n c 3 ( ) − − > m a i n main-->func3()-->main main−−>func3()−−>main构成一个线程, m a i n − − > f u n c 2 ( ) main-->func2() main−−>func2()、 m a i n − − > f u n c 1 ( ) main-->func1() main−−>func1()也都构成了一个线程
栈与线程
- 一个栈只有最下方的帧可被读写,相应的,也只有该帧对应的那个函数被激活,处于工作状态
- 因此,在创建一个新的线程时,需要为这个线程创建一个新的栈,每个栈对应一个线程
- 每个线程可调用自己栈最下方的帧中的参数和变量,并于其他的线程共享内存中的 T e x t 、 h e a p Text、heap Text、heap和 g l o b a l d a t a global data globaldata区域
- 注意:对于多线程来说,由于同一个进程空间中存在多个栈,任何一个空白区域被填满都会导致栈溢出
多线程的创建与结束
- 多线程编写相关函数
//所需头文件
#include <pthread.h>
//创建线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
//等待一个线程的结束
int pthread_join(pthread_t thread, void **retval);
//线程结束
void pthread_exit(void *retval);
- 创建线程
创建成功则返回0,创建失败则返回出错编号
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
pthread_t
, 其定义为typedef unsigned long int pthread_t,即其本质为unsigned long int,无符号长整型thread
,为指向线程标识符的指针attr
, 用来设置线程属性,后续提及void *(*start_routine) (void *)
,线程运行函数的起始地址arg
,运行函数的参数
- 等待一个线程的结束
int pthread_join(pthread_t thread, void **retval);
线程阻塞函数,调用它的函数将一直等待到被等待的线程结束为止
thread
,为被等待的线程标识符retval
,用户定义的指针,用来存储被等待线程的返回值
- 线程结束
线程结束有两个途径:
(1) 函数已经结束,调用的线程自然也就结束了
(2)通过函数pthread_exit()实现
void pthread_exit(void *retval);
retval
,函数的返回代码
pthread_join与pthread_exit区别
(1)pthread_join一般是主线程来调用,用来等待子线程的退出
(2)pthread_exit一般是子线程调用,用来结束当前线程
(3)子线程可以通过pthread_exit传递一个返回值,而主线程通过pthread_join获得该返回值
下面来看一个简单的示例:
//test.cpp
#include <iostream>
#include <stdio.h>
#include <pthread.h>
//线程处理函数
void * say_hello(void *args) {
std::cout << "hello from thread" << std::endl;
pthread_exit((void *)1);
}
int main(int argc, char *argv[]) {
pthread_t tid;
//创建一个线程
int iret = pthread_create(&tid, NULL, say_hello, NULL);
if (iret) {
std::cout << "pthread_create error: iret=" << iret << std::endl;
return iret;
}
void *retval;
//等待线程的结束
iret = pthread_join(tid, &retval);
if (iret) {
std::cout << "pthread_join error: iret=" << iret << std::endl;
return iret;
}
std::cout << "retval = " << (long)retval << std::endl;
return 0;
}
编译g++ -o test test.cpp -lpthread(或-pthread)
得到test文件,并执行:
简单分析一下:
首先主线程创建了一个新的线程,该线程的运行函数为say_hello函数,然后调用pthread_join等待该线程函数的返回,并获得返回值输出
本文只是简单介绍一下多线程,后续将会深入理解多线程
--------------------------- 2019.1.23 2019.1.23 2019.1.23更新-------------------------------------------------
添加两个线程相关函数:
- p t h r e a d pthread pthread_ s e l f ( ) self() self()函数:每个线程都有在某个给定的进程内标识自身的一个 i d id id。这个 i d id id由 p t h r e a d pthread pthread_ c r e a t e create create函数返回,一个线程使用 p t h r e a d pthread pthread_ s e l f self self取得自己的线程 i d id id
#include <pthread.h>
pthread_t pthread_slef(void);
- p t h r e a d pthread pthread_ d e t a c h detach detach函数:将指定的线程变为分离的
#include <pthread.h>
int pthread_detach(pthread_t tid);