程序:程序是由一系列的指令和逻辑组成的一个静态文件(如cpp文件),无论能不能运行,它都客观的存在于储存器中。
进程:进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位--来源于百度百科。如果你是初学者,可能你并不能真正地理解这句话。通俗地说,系统为特定的静态程序分配好运行时需要的各种资源,这个时候系统会连带地生成一个PCB(进程控制块,一种数据结构)用来记录程序运行时(这里的运行并不是指进程的运行态)的各种信息(如进程当前的状态等),这个时候你的程序就可以运行了,只需要等待CPU对其的调用,我们用进程来称呼其为程序的一次运行。
线程:在以前,进程是系统独立调度和分派的基本单位,后面由于多道处理的出现,产生了并发的概念(不明白并发的话可以先看第②点),它加大了系统的容量与对硬件的利用率。我们知道,对于单处理器的机器来说,实现并发典型的方法便是使用分时,即CPU将时间片按特定算法分发给各个进程,虽然总的计算次数可能并没有发生什么变化,但是由于CPU的计算速度越来越快,从宏观上来看,几个进程就像是在同一时间段内运行的。于是,当进程A的时间用完了之后就要切换到另一个进程B,此时计算机需要为进程A保存下结束时的状态以便下一次从上一次结束处继续执行,还需要为进程B的运行做各种准备工作,由于进程相对而言比较大,反复切换会浪费很多的资源,所以人们想能不能将系统独立调度和分派的基本单位做得更小,以减少进程切换所浪费的资源--于是线程出现了。现在,大部分的OS都是以线程为系统独立调度和分派的基本单位。另外,进程是由一个或者多个线程组成,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。
给大家举一个例子:
假如你是一个很牛逼的科学家,至少是爱因斯坦那种,呵呵,某一天你突然产生了一个念头--你要做一个机器人女朋友,她无所不能,大家可以尽情想象!一天之内你就将整个生产流程以及各种制造细节都记录在了纸上(程序)。尽管你很牛逼,但是你却很孤傲,从不发表自己的发明,结果肯定就是你比较穷,于是你缺少各种原料来实现(资源)。上帝总是很眷顾你!于是第二天你就莫名其妙有了各种原料,开始着手于组建你的无所不能的机器人女友(进程)。当然制作的过程肯定是分得很细的,如制造头,制造手等等(线程),你每花1分钟的时间来制造头就会花1分钟的时间来制造手(并发)。最后,你的女朋友做好了,尽情地享受吧!
class thread
{
public:
Thread();
virtual ~Thread();
int start (void * = NULL);
void stop();
void sleep (int);
void detach();
void * join();
bool joinable();
protected:
virtual void * run(void *) = 0;
private:
... //这里只介绍主要的方法,对于不同的库方法会有差异,不过都是大同小异。
};
stop(),sleep()这2个看名字就知道,一个停止,一个休眠等待。
start() 和run() 这2个是由区别的,执行 start() 会告诉系统创建一个新线程并就绪,但是并不一定马上运行,而是让系统选择一个合适的时间来调用 run() 来运行,这样就有了异步的可能。而 run() 的话就是将CPU腾出来立刻运行此线程,run() 可以用来确保线程的首次运行。
而 join() 和 detach() 这2个方法就显得更加难以理解了,且听我慢慢道来。
一个线程,总是会有下面2种状态之间的一种:
joinable:可会合的
detachable:分离的(不可会合的)
一个子线程被创建之后默认为 joinable ,在子线程终止之前,我们需要调用 join() 函数来将其与父线程会合,只有这样在子线程终止之后才能被摧毁,其所占有的资源(内存,端口等)才会被释放,否则会导致内存泄露。当然我们可以用 detach() 方法来将其设置为分离的,一个线程被分离之后将不再受我们的控制,可以想象成托管给了系统,当其被终止的时候会被马上摧毁。joinable() 方法可以用来检验当前是否为 joinable。
当然 join() 还被设置用来实现一个强大的功能--同步:
如果我们在主线程XX行调用了 join() ,那么在子线程终止之前,主线程会一直阻塞在XX行,这样就可以用来同步子线程和主线程了。
...
int main(int argc, char *argv[])
{
...
string recvBuf,sendBuf;
while(1)
{
recvBuf = recvMsg(); //由于涉及到网络编程,所以这里仅用recvMsg()来表示获取别人发来的消息,如果没有消息则阻塞,之后我会写一些网络编程的文章
cout << "对方向你发送:" << revcBuf << endl; //输出对方发来的信息
getline(cin,sendBuf); //输入要发送的信息至sendBuf中,如果没有输入则阻塞
sendMsg(sendBuf); //发送自己输入的信息
}
...
return 0;
}
#include
...
void getMsg()
{
...
while(1)
{
recvBuf = recvMsg();
cout << "对方向你发送:" << revcBuf << endl;
}
...
return;
}
int main(int argc, char *argv[])
{
...
string sendBuf;
thread trdRecv(getMsg); //创建子线程以完成getMsg
while(1)
{
getline(cin,sendBuf);
sendMsg(sendBuf);
}
...
return 0;
}
...
int main(int argc, char *argv[])
{
...
string sendBuf;
thread trdRecv(getMsg); //创建子线程以完成getMsg
trdRecv.join(); /*新加,这样对吗?*/
while(1)
{
getline(cin,sendBuf);
sendMsg(sendBuf);
}
...
return 0;
}