进程是资源分配的基本单位
线程是调度的基本单位
笼统来说,线程有以下优点:
- 创建一个新线程的代价要比创建一个新进程小得多
- 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
- 线程占用的资源要比进程少很多
- 能充分利用多处理器的可并行数量
- 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务
- 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
- I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。
线程的缺点也不少:
性能损失一个很少被外部事件阻塞的计算密集型线程往往无法与共它线程共享同一个处理器。如果计算密集型 线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的 同步和调度开销,而可用的资源不变。健壮性降低编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,换句话说线程之间是缺乏保护的。缺乏访问控制进程是访问控制的基本粒度,在一个线程中调用某些 OS 函数会对整个进程造成影响。编程难度提高编写与调试一个多线程程序比单线程程序困难得多
所谓健壮性,就是鲁棒性,在多线程中,任何一个线程出现崩溃的情况,整个进程都跟着玩完。
而多进程代码就不会,因为进程有独立性。
进程的多个线程共享同一地址空间 , 因此 Text Segment(代码段) 、 Data Segment(数据区) 都是共享的 , 如果定义一个函数 , 在各线程 中都可以调用, 如果定义一个全局变量 , 在各线程中都可以访问到。
除此之外, 各线程还共享以下进程资源和环境 :
- 文件描述符表
- 每种信号的处理方式(SIG_ IGN、SIG_ DFL或者自定义的信号处理函数)
- 当前工作目录
- 用户id和组id
线程共享进程数据,但也拥有自己的一部分数据 :
线程 ID一组寄存器栈errno信号屏蔽字调度优先级
每个线程都要有自己的独立的硬件上下文,也要有自己独立的栈结构。
linux没有真线程,只有轻量化进程,所以Linux OS只会提供轻量化进程的系统调用,不会直接提供线程创建的接口。
操作系统和用户之间有一层软件层,对上提供线程的相关控制接口。
然后在软件层中,将线程对应成LWP。
它并不属于操作系统,而是开发者封装的一个库。叫做 pthread原生线程库。
任何一款Linux系统都有这个库。
我们可以对mythread所回调的函数进行传参。
#include<iostream>
#include<string>
#include<pthread.h>
#include<unistd.h>
using namespace std;
void *ThreadRoutine(void*args)
{string stringname=(const char*)args;while(true){cout<<"I am new Thread "<<"threadname"<<stringname<<endl;sleep(1);}}
int main()
{pthread_t tid;pthread_create(&tid,nullptr,ThreadRoutine,(void*)"thread 1");while(true){cout<<"I am main Thread"<<endl;sleep(1);}
}
这个参数传什么都行。
可以像我一样直接传一个类。
#include<iostream>
#include<string>
#include<functional>
#include<pthread.h>
#include<unistd.h>
#include<time.h>
using namespace std;
using func_t=function<void()>;
class ThreadData
{public:ThreadData(const string&name,const uint64_t&ctime,func_t f):threadname(name),createtime(ctime),func(f){}public:string threadname;uint64_t createtime;func_t func;
};
void *ThreadRoutine(void*args)
{ThreadData*td=static_cast<ThreadData*>(args);while(true){cout<<"I am new Thread "<<td->threadname<<' '<<td->createtime<<' '<<endl;td->func();sleep(1);}}
void print()
{cout<<"我是线程执行的大任务的一部分"<<endl;
}
int main()
{pthread_t tid;ThreadData*td=new ThreadData("Thread 1",uint64_t(time(nullptr)),print);pthread_create(&tid,nullptr,ThreadRoutine,td);while(true){cout<<"I am main Thread"<<endl;sleep(1);}
}
也可以像下面这样多线程传参。
#include<iostream>
#include<string>
#include<functional>
#include<vector>
#include<pthread.h>
#include<unistd.h>
#include<time.h>
using namespace std;
using func_t=function<void()>;
const int threadnum=5;
class ThreadData
{public:ThreadData(const string&name,const uint64_t&ctime,func_t f):threadname(name),createtime(ctime),func(f){}public:string threadname;uint64_t createtime;func_t func;
};
void *ThreadRoutine(void*args)
{ThreadData*td=static_cast<ThreadData*>(args);while(true){cout<<"I am new Thread "<<td->threadname<<' '<<td->createtime<<' '<<endl;td->func();sleep(1);}}
void print()
{cout<<"我是线程执行的大任务的一部分"<<endl;
}
int main()
{for(int i=0;i<threadnum;i++){pthread_t tid;char threadname[64];snprintf(threadname,sizeof threadname,"%s-%d","thread",i);ThreadData*td=new ThreadData(threadname,uint64_t(time(nullptr)),print);pthread_create(&tid,nullptr,ThreadRoutine,td);}while(true){cout<<"I am main Thread"<<endl;sleep(1);}
}
上面提到多线程代码健壮性低。
一个线程出错,全都会崩溃。