社区
Linux/Unix社区
帖子详情
请问Linux下线程开销为什么这么大?一个线程要占用近10M内存
cpio
2011-07-21 05:53:24
32位机器,当创建到200多个线程的时候,虚拟内存占用达到3G,此时再也不能创建新线程了。
有没有系统设置可以减小线程开销?Windows下似乎线程基本不占内存。
...全文
599
8
打赏
收藏
请问Linux下线程开销为什么这么大?一个线程要占用近10M内存
32位机器,当创建到200多个线程的时候,虚拟内存占用达到3G,此时再也不能创建新线程了。 有没有系统设置可以减小线程开销?Windows下似乎线程基本不占内存。
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
8 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
jackyjkchen
2011-07-21
打赏
举报
回复
[Quote=引用 7 楼 cpio 的回复:]
难道Windows是所有线程共享栈?
[/Quote]
windows默认栈1M
cpio
2011-07-21
打赏
举报
回复
难道Windows是所有线程共享栈?
cpio
2011-07-21
打赏
举报
回复
用ulimit -s 1024就好了,默认是8196,所以每次接近10M。
不知道默认为什么这么大,据说Solaris才几百k。
jackyjkchen
2011-07-21
打赏
举报
回复
[Quote=引用 4 楼 cpio 的回复:]
使用QT4.7.2测试的,创建线程使用的QThread,代码很简单,从QThread继承,在run虚函数里面写的
while (true)
{
sleep(100);
}
然后开始创建这个QThread。
按jackyjkchen说的,是不是新线程会跟初始进程占用的内存一样多?那这样的话,如果初始进程占用内存多的话,它创建的新线程就会占得多?
[/Quote]
你默认栈开了多大,可能线程继承了进程的栈设置
cpio
2011-07-21
打赏
举报
回复
使用QT4.7.2测试的,创建线程使用的QThread,代码很简单,从QThread继承,在run虚函数里面写的
while (true)
{
sleep(100);
}
然后开始创建这个QThread。
按jackyjkchen说的,是不是新线程会跟初始进程占用的内存一样多?那这样的话,如果初始进程占用内存多的话,它创建的新线程就会占得多?
昵称很不好取
2011-07-21
打赏
举报
回复
从程序方面找找原因吧
xunxun
2011-07-21
打赏
举报
回复
[Quote=引用 1 楼 jackyjkchen 的回复:]
Linux下的线程就是一种进程,所以Linux线程的开销是极大的。Windows是原生的线程。
但是你说200个线程就3G内存有点扯,是不是你每个线程的堆栈开太大了?
Linux下跑几百个进程都是常见的
[/Quote]
我也觉得是每个线程的堆栈
不过为啥说Linux下线程就是一种进程呢?OpenMP基于pthreads的,运行时也只看到一个进程啊
jackyjkchen
2011-07-21
打赏
举报
回复
Linux下的线程就是一种进程,所以Linux线程的开销是极大的。Windows是原生的线程。
但是你说200个线程就3G内存有点扯,是不是你每个线程的堆栈开太大了?
Linux下跑几百个进程都是常见的
一个
进程池的服务器程序
一个
进程池的服务器程序 下面做了非常简单的http服务器,该服务器只能接收Get请求。 流程大概如下: 1,父进程listen,创建pipe(下面所有父子进程之间的通信都用该pipe) 2,父进程预fork n个子进程 3,各个子进程accept(listenfd),即所有子进程竞争accept请求。由于listenfd是在fork之前就有的,所以所有子进程都可以访问到,不需用到“进程间文件描述符传递”问题; 4,子进程每accept到
一个
请求都告诉父进程,父进程把请求数加1;子进程没完成
一个
请求,父进程把请求数减1;当父进程发现请求数 >= 子进程数时,父进程创建新的子进程,并把子进程数加1(当然子进程数有个预先上限);当父进程发现子进程数大于请求数加1时,父进程杀死多余的子进程。 总的来说,思想是让子进程accept并处理请求,父进程通过子进程发来的信息控制请求数与子进程数之间的关系。 代码如下: 代码如下: #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PRECHILD 5 #define MAXCHILD 50 #define BUFSIZE 4096 #define PIDPATH "pid" #define head503 "HTTP/1.1 503 Service unavailable\r\n" #define head404 "HTTP/1.1 404 Not Found\r\n" #define head200 "HTTP/1.1 200 0K\n\rContent—Type: text/html\n\rContent—Length: " int len503, len404, len200; int fd1[2], fd2[2]; typedef struct { pid_t pid; char status; // 'n' means new request; 'f' means finish the request } REPORT; void answer(int listenfd) { int connfd; char buf[BUFSIZE]; int count; int pid = getpid(); struct sockaddr_in cliaddr; int size = sizeof(cliaddr); char comm; REPORT rep; rep.pid = pid; while (1) { connfd = accept(listenfd, (struct sockaddr *)&cliaddr,(socklen_t *)&size ); //子进程accept请求 rep.status = 'n'; if (write(fd1[1], &rep, sizeof(rep)) < 0) { //通知父进程已经accept了请求 perror("write pipe new failed"); exit(-1); } count = read(connfd, buf, BUFSIZE); char req[10]; char filepath[256]; sscanf(buf, "%s%s", req, filepath + 1); filepath[0] = '.'; if (strcmp("GET", req) != 0) {//503 write(connfd, head503, len503); //goto err_out; close(connfd); exit(-1); } char content[BUFSIZE]; struct stat stbuf; if (lstat(filepath, &stbuf) != 0) { int err = errno; if (err == ENOENT) {//404 write(connfd, head404, len404); } close(connfd); exit(-1); } count = write(connfd, head200, len200); u_int filesize = stbuf.st_size; sprintf(content, "%u\n\r\n\r", filesize); count = write(connfd, content, strlen(content)); FILE *fp = fopen(filepath, "r"); if (fp == NULL) { printf("open file %s failed\n", filepath); close(connfd); exit(-1); } while((count = fread(content, 1, sizeof(content), fp)) > 0) { //printf("%s", content); if (write(connfd, content, count) != count) { printf("write failed\n"); } } fclose(fp); close(connfd); rep.status = 'f'; if (write(fd1[1], &rep, sizeof(rep)) < 0) {//告诉父进程自己处理完了请求 perror("write pipe finish failed"); exit(-1); } if (read(fd2[0], &comm, 1) < 1) {//等待来自父进程的命令 perror("read pipe failed"); exit(-1); } //printf("[%d] reve %c from pa\n", pid, comm); if (comm == 'e') { //收到exit命令 printf("[%d] exit\n", pid); exit(-1); } else if (comm == 'c') { //收到继续accept的命令 printf("[%d] continue\n", pid); } else { printf("[%d] comm : %c illeagle\n", pid, comm); } } } void usage() { printf("Usage: http-serv port\n"); } int write_pid() { int fd; if ((fd = open(PIDPATH, O_WRONLY | O_TRUNC | O_CREAT, S_IWUSR)) < 0){ perror("open pidfile faild"); return -1; } struct flock lock; lock.l_type = F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; if (fcntl(fd, F_SETLK, &lock) == -1) { int err = errno; perror("fcntl faild"); if (err == EAGAIN) { printf("Another http-serv process is running now!\n"); } return -1; } return 0; } void daemon_init() { //clear file creation mask; umask(0); //become a session leader if (fork() != 0) exit(-1); if (setsid() < 0) exit(-1); //make sure can be never get the TTY control if (fork() != 0) exit(-1); //may chdir here int i; for (i = 0; i < 1024; i++) close(i); /* * Attach file descriptors 0, 1, and 2 to /dev/null. */ int fd0, fd1, fd2; fd0 = open("/dev/null", O_RDWR); fd1 = dup(0); fd2 = dup(0); if (fd0 != 0 || fd1 != 1 || fd2 != 2) { printf("init failed\n"); exit(-1); } } int main(int argc, char **argv) { int listenfd; struct sockaddr_in servaddr; pid_t pid; if (argc != 2) { usage(); return -1; } signal(SIGCHLD, SIG_IGN); len200 = strlen(head200); len404 = strlen(head404); len503 = strlen(head503); daemon_init(); //转为后台程序,如需打印调试,把这行注释掉 if (write_pid() < 0) //避免同时有多个该程序在运行 return -1; if (pipe(fd1) < 0) { perror("pipe failed"); exit(-1); } if (s_pipe(fd2) < 0) { perror("pipe failed"); exit(-1); } int port = atoi(argv[1]); //initialize servaddr and listenfd... bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(port); listenfd = socket(AF_INET, SOCK_STREAM, 0); bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); listen(listenfd, 1000); int i; for (i = 0; i < PRECHILD ; i++) { //父进程预fork 子进程 if ((pid = fork()) < 0) { perror("fork faild"); exit(3); } else if (pid == 0) { answer(listenfd); } else { printf("have create child %d\n", pid); } } char e = 'e'; char c = 'c'; int req_num = 0; int child_num = PRECHILD; REPORT rep; while (1) { //printf("req_num = %d, child_num = %d\n", req_num, child_num); if (read(fd1[0], &rep, sizeof(rep)) < sizeof(rep)) {//等待子进程发来消息 perror("parent read pipe failed"); exit(-1); } //printf("parent: receive from %d\n", pid); if (rep.status == 'n') {//子进程刚accept了新的请求 req_num ++; printf("parent: %d have receive new request\n", rep.pid); if (req_num >= child_num && child_num <= MAXCHILD) { //请求数过多,创建更多子进程 if ((pid = fork()) < 0) { perror("fork faild"); exit(3); } else if (pid == 0) { answer(listenfd); } else { printf("have create child %d\n", pid); child_num ++; } } } else if (rep.status == 'f') {//子进程刚处理完了
一个
请求 req_num --; //printf("parent: %d have finish a request\n", rep.pid); if (child_num > (req_num + 1) && child_num > PRECHILD) {//子进程数过多,删除多余的子进程 if (write(fd2[1], &e, sizeof(e)) < sizeof(e)) { perror("pa write pipe failed"); exit(-2); } //printf("tell child exit\n"); child_num --; } else { if (write(fd2[1], &c, sizeof(c)) < sizeof(c)) {//让子进程继续等待accept perror("pa write pipe failed"); exit(-2); } //printf("tell child continue\n"); } } } return 0; } 利用fork()创建多个子进程 11:09 pm on Oct 23rd 2010 greenMay 之间我学习了创建
一个
子进程,也大致理解了子进程与父进程的关系。今天无意间遇到
一个
创建多个子进程的问题,结果还发现了点小bug,现在写下来和大家分享。 我需要实现的目标如下:编写一段源程序,使系统调用fork()创建两个子进程,当此程序运行时,在系统中有
一个
父进程和两个子进程活动。让每
一个
进程在屏幕上显示
一个
字符:父进程显示字符“a”;子进程分别显示字符“b”和字符“c”。 一开始我的主要代码如下: view source print? 01 int main() 02 { 03 pid_t child1; 04 pid_t child2; 05 child1 = fork(); 06 child2 = fork(); 07 if(child1 == 0) 08 { 09 printf("Child1:a\n"); 10 return 0; 11 } 12 if(child2 == 0) 13 { 14 printf("Child2:b\n"); 15 return 0; 16 } 17 else 18 { 19 waitpid(child1,NULL,0); 20 waitpid(child2,NULL,0); 21 printf("Parent:c\n"); 22 } 23 return 0; 24 } 奇怪的是,我得到的是这样
一个
结果: Child1:a Child1:a Child2:b Parent:c 竟然有两个Child1。可是我的代码里明明只是让Chidl1打印一次啊。搜索到一篇好的博文。文章仔细分析了和我几乎相同的情况。事实上,是我的粗心和对fork()的理解不深刻导致了上述的奇怪问题。 我们知道,fork()之后,我们还是首先执行的是父进程,也就是如下代码段: view source print? 1 waitpid(child1,NULL,0); 2 waitpid(child2,NULL,0); 3 printf("Parent:c\n"); 然后waitpid(child1,NULL,0),进入child1的执行。child1将要执行的是如下的的代码段: view source print? 1 child2 = fork(); 2 if(child1 == 0) 3 { 4 printf("Child1:a\n"); 5 return 0; 6 } 注意,第一行的那个child2 = fork()!这就意味着对于child1来说,它自己又要创建
一个
子进程,这时候他成为了父亲。这时候,它有
一个
儿子child2,但是这个child2不同与我们刚才定义的那个child2,这个child2其实是parent的孙子。之所以又打印了一边Child1。如果加上如下代码就明白了: view source print? 01 child2 = fork(); 02 if(child1 == 0) 03 { 04 if(child2 == 0) 05 { 06 printf("GrandChild!\n"); 07 } 08 printf("Child1:a\n"); 09 return 0; 10 } 这时候将出现: Child1:a GrandChild! Child1:a Child2:b Parent:c 恩,这就很明白了!我无意间多调用了一次child2=fork(); 所以,如果要达到我最初的目的,需要改变child2的fork()的位置: view source print? 01 #include
02 #include
03 #include
04 #include
05 int main() 06 { 07 pid_t child1; 08 pid_t child2; 09 child1 = fork(); 10 child2 = fork(); 11 if(child1 == 0) 12 { 13 printf("Child1:a\n"); 14 return 0; 15 } 16 if(child2 == 0) 17 { 18 printf("Child2:b\n"); 19 return 0; 20 } 21 else 22 { 23 waitpid(child1,NULL,0); 24 waitpid(child2,NULL,0); 25 printf("Parent:c\n"); 26 } 27 return 0; 28 } 我参照的那个博文最后给出了
一个
更为普遍的fork()创建多进程的程序框架: view source print? 01 pid_t create_child() 02 { 03 pid_t p = fork(); 04 if( p == 0 ) 05 { 06 printf("in child %d\n", getpid()); 07 //do something 08 return 0; 09 } 10 return p; 11 } 12 int main(void) 13 { 14 pid_t p1 = create_child(); 15 pid_t p2 = create_child(); 16 17 int st1, st2; 18 waitpid( p1, &st1, 0); 19 waitpid( p2, &st2, 0); 20 printf("in parent, pid = %d\n", getpid()); 21 printf("in parent, child 1 exited with %d\n", st1); 22 printf("in parent, child 2 exited with %d\n", st2); 23 return 0; 24 } 注意到,期中的create_child()函数最后有
一个
return p。这个return p将pid返回给了父进程,其实也是将子进程对于CPU的控制权交还给了父进程,这样就避免了多个子进程在创建之时互相影响了。 可以说,今天的这个问题真是
一个
有趣的事情。代码有的时候就是这么奇怪~ 最后,向我引用的那篇文章致敬!
Linux
内核对多进程和多
线程
的支持方式:
线程
机制支持并发程序设计技术,在多处理器上能真正保证并行处理。而在
linux
实现
线程
很特别,
linux
把所有的
线程
都当作进程实现。
linux
下
线程
看起来就像普通进程(只是该进程和其他进程共享资源,如地址空间)。上述机制与Microsoft windows或是Sun Solaris实现差异很大。
Linux
的
线程
实现是在核外进行的,核内提供的是创建进程的接口do_fork()。内核提供了两个系统调用__clone()和fork(),最终都用不同的参数调用do_fork()核内API。 do_fork() 提供了很多参数,包括CLONE_VM(共享
内存
空间)、CLONE_FS(共享文件系统信息)、CLONE_FILES(共享文件描述符表)、CLONE_SIGHAND(共享信号句柄表)和CLONE_PID(共享进程ID,仅对核内进程,即0号进程有效)。当使用fork系统调用产生多进程时,内核调用do_fork()不使用任何共享属性,进程拥有独立的运行环境。当使用pthread_create()来创建
线程
时,则最终设置了所有这些属性来调用__clone(),而这些参数又全部传给核内的do_fork(),从而创建的”进程”拥有共享的运行环境,只有栈是独立的,由 __clone()传入。 即:
Linux
下不管是多
线程
编程还是多进程编程,最终都是用do_fork实现的多进程编程,只是进程创建时的参数不同,从而导致有不同的共享环境。
Linux
线程
在核内是以轻量级进程的形式存在的,拥有独立的进程表项,而所有的创建、同步、删除等操作都在核外pthread库中进行。pthread 库使用
一个
管理
线程
(__pthread_manager() ,每个进程独立且唯一)来管理
线程
的创建和终止,为
线程
分配
线程
ID,发送
线程
相关的信号,而主
线程
pthread_create()) 的调用者则通过管道将请求信息传给管理
线程
。 很多朋友都说使用多
线程
的好处是资源
占用
少,其隐含之意就是说进程
占用
资源比
线程
多,对吧?但实际上
Linux
下多进程是否就真的点用很多资源呢?暂且不说进程是否比
线程
占用
资源多,就进程
占用
资源的多少情况而言,
Linux
确实是做得相当节省的。产生
一个
多进程时肯定是要产生的一点
内存
是要复制进程表项,即
一个
task_struct结构,但这个结构本身做得相当小巧。其它对于
一个
进程来说必须有的数据段、代码段、堆栈段是不是全盘复制呢?对于多进程来说,代码段是肯定不用复制的,因为父进程和各子进程的代码段是相同的,数据段和堆栈段呢?也不一定,因为在
Linux
里广泛使用的
一个
技术叫copy-on-write,即写时拷贝。copy-on-write意味着什么呢?意味着资源节省,假设有
一个
变量x在父进程里存在,当这个父进程创建
一个
子进程或多个子进程时这个变量x是否复制到了子进程的
内存
空间呢?不会的,子进程和父进程使用同
一个
内存
空间的变量,但当子进程或父进程要改变变量x的值时就会复制该变量,从而导致父子进程里的变量值不同。父子进程变量是互不影响的,由于父子进程地址空间是完全隔开的,变量的地址可以是完全相同的。
Linux
的”
线程
”和”进程”实际上处于
一个
调度层次,共享
一个
进程标识符空间,这种限制使得不可能在
Linux
上实现完全意义上的POSIX
线程
机制,因此众多的
Linux
线程
库实现尝试都只能尽可能实现POSIX的绝大部分语义,并在功能上尽可能逼
近
。
Linux
进程的创建是非常迅速的。内核设计与实现一书中甚至指出
Linux
创建进程的速度和其他针对
线程
优化的操作系统(Windows,Solaris)创建
线程
的速度相比,测试结果非常的好,也就是说创建速度很快。由于异步信号是内核以进程为单位分发的,而
Linux
Threads的每个
线程
对内核来说都是
一个
进程,且没有实现”
线程
组”,因此,某些语义不符合POSIX标准,比如没有实现向进程中所有
线程
发送信号,README对此作了说明。
Linux
Threads中的
线程
同步很大程度上是建立在信号基础上的,这种通过内核复杂的信号处理机制的同步方式,效率一直是个问题。
Linux
Threads 的问题,特别是兼容性上的问题,严重阻碍了
Linux
上的跨平台应用(如Apache)采用多
线程
设计,从而使得
Linux
上的
线程
应用一直保持在比较低的水平。在
Linux
社区中,已经有很多人在为改进
线程
性能而努力,其中既包括用户级
线程
库,也包括核心级和用户级配合改进的
线程
库。目前最为人看好的有两个项目,
一个
是RedHat公司牵头研发的NPTL(Native Posix Thread Library),另
一个
则是IBM投资开发的NGPT(Next Generation Posix Threading),二者都是围绕完全兼容POSIX 1003.1c,同时在核内和核外做工作以而实现多对多
线程
模型。这两种模型都在一定程度上弥补了
Linux
Threads的缺点,且都是重起炉灶全新设计的。 综上所述的结论是在
Linux
下编程多用多进程编程少用多
线程
编程。 IBM有个家伙做了个测试,发现切换
线程
context的时候,windows比
linux
快一倍多。进出最快的锁(windows2k的 critical section和
linux
的pthread_mutex),windows比
linux
的要快五倍左右。当然这并不是说
linux
不好,而且在经过实际编程之后,综合来看我觉得
linux
更适合做high performance server,不过在多
线程
这个具体的领域内,
linux
还是稍逊windows一点。这应该是情有可原的,毕竟unix家族都是从多进程过来的,而 windows从头就是多
线程
的。 如果是UNIX/
linux
环境,采用多
线程
没必要。 多
线程
比多进程性能高?误导! 应该说,多
线程
比多进程成本低,但性能更低。 在UNIX环境,多进程调度
开销
比多
线程
调度
开销
,没有显著区别,就是说,UNIX进程调度效率是很高的。
内存
消耗方面,二者只差全局数据区,现在
内存
都很便宜,服务器
内存
动辄若干G,根本不是问题。 多进程是立体交通系统,虽然造价高,上坡下坡多耗点油,但是不堵车。 多
线程
是平面交通系统,造价低,但红绿灯太多,老堵车。 我们现在都开跑车,油(主频)有的是,不怕上坡下坡,就怕堵车。 高性能交易服务器中间件,如TUXEDO,都是主张多进程的。实际测试表明,TUXEDO性能和并发效率是非常高的。TUXEDO是贝尔实验室的,与UNIX同宗,应该是对UNIX理解最为深刻的,他们的意见应该具有很大的参考意义 1. 散沙 2010年7月10日08:43 回复 | 引用 | #1 文章很有深度,我们把握
一个
尺度就可以了,在windows下使用
线程
,unix下则使用进程就可以了 2. rjoo 2010年9月9日13:49 回复 | 引用 | #2 错的太多了,博主,应该看看新资料了。 现在都2010年了,NPTL早就取代了老的
Linux
thread。而且通常多
线程
有性能优势,但是多进程更稳定,并且通常性能瓶颈不在于是进程模型还是
线程
模型而在于IO。 3. rjoo 2010年9月9日13:56 回复 | 引用 | #3 关于那个critical section和pthread_mutex_t,critical section本质上是
一个
自旋锁,短期锁当然快,不知道你说的那个IBM的哥们怎么比的,要比也该是和pthread_spinlock_t比。 4. admin 2010年9月9日17:28 回复 | 引用 | #4 rjoo挺热心的,呵呵,这篇文章不是我写的,但有几个地方我可以解答一下: 1.
Linux
下没有
线程
的概念,pthread
线程
实质是通过轻量级进程实现的。你说瓶颈在IO,这一点我很赞同你的意见,作者如果能再写个IO操作的文章来的话就会更好了。 2. mutex和critical section的确是不能比的。
一个
涉及到内核,
一个
没有涉及到内核。呵呵,很佩服你对这些东西的掌握程度,有机会多交流。 ^_^ 5. 定时 2010年9月9日17:40 回复 | 引用 | #5 我们组的最
近
项目的经验告诉我们能用多进程不用多
线程
,多
线程
安全编程难,而且锁会早成效率很低,甚至不如单
线程
,你说的NPTL我知道,他只是多
线程
优化了并不能改变多
线程
安全编程的问题,锁的问题。谢谢指教,实践出真知。 @rjoo 6. 定时 2010年9月9日17:44 回复 | 引用 | #6 你说的锁,我确实不太了解,但是我们leader对它很了解,就是最
近
的
一个
项目,锁搞得他很郁闷,他也终于同意我的关键,尽可能不用多
线程
。 @rjoo 7. rjoo 2010年9月29日13:41 回复 | 引用 | #7 @admin
Linux
下没有
线程
的概念,pthread
线程
实质是通过轻量级进程实现的—这是2.4内核以前的情况(实际上是2.0时引入的,那可实在是太久了),2.4内核引入NGPL,2.6内核
线程
支持改为NPTL。NPTL实现的是1:1的
线程
模型(有资料说Win也是这种实现,虽然不太确定,但我觉得可能性很大),而NGPT虽然是理论上最先进的m:n
线程
模型,但最后实现出来的性能差NPTL一大截,最后被抛弃。看看文中说法就知道要么文章写的很早,要么作者看了一堆十年前的资料。 给个链接: http://www.kegel.com/c10k.html#threads.
linux
threads 8. finalday 2010年10月15日17:26 回复 | 引用 | #8 忍不住跳出来说,作者对并发编程的理解还不行。 比如说锁的问题,说得好像是多
线程
才需要的东西一样。如果
一个
应用多进程时完全不用锁,多
线程
也就多
一个
轻量级锁——锁一下,各回各家,每个
线程
用自己的专有存储,之后不就和多进程一样了?这样会被搞得很郁闷?当然不会。所以说明那个应用对于数据共享的需求不是这么简单,既然不是这么简单,多进程程序一样要加锁。多进程的加解锁代价可比多
线程
大得多了,共享数据和协作也麻烦多了。 多
线程
编程难不难?难,但这是由于并发本身的难度引起的。“锁”,“安全编程”不管是多
线程
还是多进程都一样会遇到。 多
线程
的最大优点是数据共享和协作方便。 多进程的最大优点是挂了
一个
进程不会影响其他进程,资源也不会泄露,故比较能容忍程序员犯错。 至于两者裸奔比性能,真的没啥意义。
Linux
下创建
一个
线程
占用
多少
内存
在前面的博客进程分配资源中,我们了解到,在32位平台下,系统会给
一个
进程分配4G的虚拟
内存
供进程使用。 因此,我们知道,
一个
进程被创建时将被分配有4G的虚拟
内存
。事实上,并不是每次都会用完这4G
内存
的,下面的例子可以看到。 #include <stdio.h> #include <unistd.h> int main(){ while(1){ ...
Linux
下
线程
理解
线程
,在操作系统当中这是
一个
相当重要的概念,
线程
的存在是为了解决在
一个
进程当中执行多个执行分支的任务,举
一个
很简单的例子:当你在用某个下载软件的时候,相当于你在运行该进程,而你在通过该软件进行下载时,很明显你在同一时间并不是只能进行
一个
下载任务,而且你在下载的时候,你可以使用键盘,鼠标来执行其他任务,而这些任务都是在同
一个
进程中在跑,这就是多
线程
的强大之处。
Linux
下
线程
详解
线程
与进程 为什么有了进程的概念后,还要再引入
线程
呢?使用多
线程
到底有哪些好处?什么的系统应该选用多
线程
?我们首先必须回答这些问题。 使用多
线程
的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。我们知道,在
Linux
系统下,启动
一个
新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于
一个
进程中的多个
014
Linux
线程
及
线程
控制相关函数
linux
线程
概念及
线程
控制函数
Linux/Unix社区
23,121
社区成员
74,507
社区内容
发帖
与我相关
我的任务
Linux/Unix社区
Linux/Unix社区 应用程序开发区
复制链接
扫一扫
分享
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章