进程和线程的区别:
详细的可以参考这样文档进程和线程的区别(超详细)-CSDN博客
核心比喻
-
进程 = 一个工厂:这个工厂拥有独立的资源(厂房、原材料、资金、电力)。每个工厂之间是相互隔离的,一个工厂着火不会直接影响另一个工厂。
-
线程 = 工厂里的工人:多个工人在一个工厂里协同工作,他们共享工厂的所有资源(厂房、原材料)。工人们可以独立地执行不同的任务(流水线),但他们需要沟通和协调,因为他们在共用同一个空间的资源。
详细区别对比表
维度 | 进程 (Process) | 线程 (Thread) |
---|---|---|
基本定义 | 资源分配的基本单位。一个正在执行的程序实例。 | CPU调度和执行的基本单位。是进程内部的一个执行流。 |
资源拥有 | 拥有独立的系统资源(如内存、I/O设备、文件等)。每个进程都有自己独立的地址空间。 | 不拥有系统资源,但共享其所属进程的全部资源。每个线程拥有自己独立的栈和寄存器。 |
开销 | 大。创建、销毁、切换进程需要分配和回收独立的内存空间、资源表等,开销较大。 | 小。创建、销毁、切换线程只需分配栈和寄存器,共享同一片内存空间,开销远小于进程。 |
通信方式 | 复杂。进程间通信(IPC)需要借助操作系统提供的机制,如:管道、消息队列、共享内存、信号量、Socket等。 | 简单。线程间通信非常方便,因为它们共享进程的全局变量、堆等数据,直接读写即可。但需要同步机制(如互斥锁)来避免冲突。 |
独立性 | 高。一个进程崩溃后,在保护模式下一般不会影响其他进程。稳定性高,隔离性好。 | 低。一个线程崩溃会导致整个进程崩溃,从而影响该进程下的所有其他线程。稳定性低,相互影响。 |
性能影响 | 进程间切换涉及地址空间的切换,CPU高速缓存(Cache)失效率高,性能损耗大。 | 线程切换只在同一地址空间内,CPU高速缓存不易失效,性能损耗小。 |
并发性 | 进程之间可以并发执行。 | 线程之间不仅可以并发执行,甚至可以实现真正的并行(在多核CPU上)。 |
从操作系统角度理解
操作系统会为每个进程维护一个进程控制块(PCB),这是一个庞大的数据结构,记录了进程的所有信息(PID、状态、优先级、内存指针等)。而线程也有自己的线程控制块(TCB),但它记录的信息要少得多(主要是线程ID、寄存器、栈指针等),因为它的大部分资源信息都指向其所属的PCB。
当进行进程切换时,操作系统需要切换整个地址空间(更换页表),这是一个相对沉重的操作。而线程切换只需切换线程的私有数据(如栈和寄存器),效率高得多。
总结与联系
-
包含关系:一个进程至少包含一个线程(主线程),也可以拥有多个线程。
-
设计目的:
-
进程 是为了更好地使多道程序并发执行,提高资源利用率和系统吞吐量。它强调的是“资源分配的独立性”。
-
线程 是为了减少程序并发执行时的时空开销,提高操作系统的并发性能。它强调的是“计算执行的并行性”。
-
-
如何选择:
-
需要安全稳定、任务之间隔离要求高时(例如Chrome浏览器每个标签页是一个独立进程),用进程。
-
需要极致性能、大量数据共享、频繁切换时(例如Web服务器同时处理多个请求、视频解码、文字处理软件的后台保存和打字),用多线程。
-
简单来说,进程是资源的容器,而线程是CPU执行的单元。线程依托于进程而存在,共享进程的资源,使得同一个应用程序内的多个任务可以更高效地协作。
线程和进程的代码
线程:
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<strings.h>
#include<unistd.h>
#include<ctype.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include<sys/wait.h>
#include<pthread.h>
#define SERV_PORT 8000
#define MAXLINE 80//打印报错信息
#define prrexit(msg){ \perror(msg); \exit(1); \}//子线程
void *up_server(void *arg){//获取自己的线程id,自我释放pthread_detach(pthread_self());//进行安全的类型转换int connfd=(int)(intptr_t)arg;char buff[MAXLINE];int n,i;while(1){n=read(connfd,buff,MAXLINE);if(n<=0){perror("read error or connections closed");break;}write(1,buff,n);if(strncmp(buff,"quit",4)==0){break;}for(i = 0; i < n ; i++)buff[i]=toupper(buff[i]);write(connfd,buff,n);}close(connfd);//正常退出return (void *)0;
}int main(){struct sockaddr_in serveraddr,claddr;int listenfd, connfd;socklen_t claddr_len;// char buff[MAXLINE];char str[INET_ADDRSTRLEN];int n,i;listenfd =socket(AF_INET,SOCK_STREAM,0);if(listenfd<0){prrexit("socket");}//服务器ip地址,端口初始化bzero(&serveraddr,sizeof(serveraddr));serveraddr.sin_family=AF_INET;serveraddr.sin_port = htons(SERV_PORT);serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);if(bind(listenfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0)prrexit("bind");if(listen(listenfd,3)<0)prrexit("listen");printf("Accepting connections...\n");while(1){claddr_len= sizeof(claddr);connfd=accept(listenfd,(struct sockaddr *)&claddr,&claddr_len);if(connfd<0)prrexit("accept");printf("received from %s:%d\n",inet_ntop(AF_INET,&claddr.sin_addr,str,sizeof(str)),ntohs(claddr.sin_port));/*多进程pid_t pid= fork();if(pid<0){prrexit("fork");}//父进程 :等待 创建连接if(pid > 0){close(connfd);//回收进程资源while(waitpid(-1,NULL,WNOHANG)>0){ };continue;}close(listenfd);*///多线程pthread_t tid;pthread_create(&tid,NULL,up_server,(void *)(intptr_t)connfd);printf("new thread is %#lx\n",tid);}return 0;
}
补充一下,因为实现线程时候调用了pthread库的函数,所以需要额外链接上 -lpthread库用以实现。
进程:
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<strings.h>
#include<unistd.h>
#include<ctype.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include<sys/wait.h>#define SERV_PORT 8000
#define MAXLINE 80//打印报错信息
#define prrexit(msg){ \perror(msg); \exit(1); \
}int main(){struct sockaddr_in serveraddr,claddr;int listenfd, connfd;socklen_t claddr_len;char buff[MAXLINE];char str[INET_ADDRSTRLEN];int n,i;listenfd =socket(AF_INET,SOCK_STREAM,0);if(listenfd<0){prrexit("socket");}//服务器ip地址,端口初始化bzero(&serveraddr,sizeof(serveraddr));serveraddr.sin_family=AF_INET;serveraddr.sin_port = htons(SERV_PORT);serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);if(bind(listenfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0)prrexit("bind");if(listen(listenfd,3)<0)prrexit("listen");printf("Accepting connections...\n");while(1){claddr_len= sizeof(claddr);connfd=accept(listenfd,(struct sockaddr *)&claddr,&claddr_len);if(connfd<0)prrexit("accept");printf("received from %s:%d\n",inet_ntop(AF_INET,&claddr.sin_addr,str,sizeof(str)),ntohs(claddr.sin_port));pid_t pid= fork();if(pid<0){prrexit("fork");}//父进程 :等待 创建连接if(pid > 0){close(connfd);//回收进程资源while(waitpid(-1,NULL,WNOHANG)>0){ };continue;}close(listenfd); //读,写,返回while(1){n=read(connfd,buff,MAXLINE);if(n<=0){perror("read error or connections closed");break;}write(1,buff,n);if(strncmp(buff,"quit",4)==0){break;}for(i = 0; i < n ; i++)buff[i]=toupper(buff[i]);write(connfd,buff,n);}close(connfd);}return 0;
}