说到多进程和多线程,我就想起了《The art of Multiprocessor Programming》中的第一章的例子(我就看了第一章)

On the first day of your new job, your boss asks you to find all primes between 1 and 10^10(never mind why), using a parallel machine that supports ten concurrent threads. This machine is rented by the minute, so the longer your program takes, the more it costs. You want to make a good impression. What do you do?

我对多线程编程不是很熟,所以想用这个例子学习一下多线程编程。

单线程编程

如果不会用线程,那么就用最简单的单线程解决这个问题。

  1. //example1.c
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <math.h>
  5. long long isPrime(int num)
  6. {
  7. long long i, s;
  8. s = (long long)sqrt(double(num));
  9. for(i = 2; i < s; i++)
  10. if(num % i == 0)
  11. return 0;
  12. return 1;
  13. }
  14. int main()
  15. {
  16. long long i,primes_count = 0;
  17. for(i = 1 ; i <= 10000000000L; i++)
  18. primes_count +=  isPrime(i);
  19. printf("%lld primes);
  20. return 0;
  21. }

注意:编译时加上-lm,gcc -lm example1.c  ; 打印long long整数要用%lld

如果真用这段代码跑10000000000L,估计几个小时跑不完,几天不知道能跑完吗。我打算在16核的机器上跑一下,不过16核和单核一样,因为是单线程。

多线程方法1

如果会使用线程,一个简单的方法是10个线程平分这些数。

-------------------------------------------------------------------------------------------

pthread相关数据结构和函数

pthread_t 调用pthread_t返回的线程号,就是一个unsigned int;

int pthread_create(pthread_t *, pthread_attr_t *,  void*  (*) (void*) , void*);

第一个参数是一个pthread_t,第二个是pthread_attr_t,具体看下面的用法,第三个是线程要运行的主函数,第四个是要给这个函数的参数。

(void*) (*) (void*) 是一个函数类型,就是类似于 void *  run (void*)的函数。

void pthread_exit() 线程退出

int pthread_join(pthread_t *, void **) 主线程等待子线程退出,第二个参数直接用NULL就行

----------------------------------------------------------------------------------------------------------

  1. //example2.c
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <pthread.h>
  5. #include <sys/types.h>
  6. #include <unistd.h>
  7. #include <math.h>
  8. long long isPrime(long long num)
  9. {
  10. long long i, s;
  11. s = (long long)sqrt((double)num);
  12. for(i = 2; i < s; i++)
  13. if(num % i == 0)
  14. return 0;
  15. return 1;
  16. }
  17. void * run(void * param)
  18. {
  19. long long start,end;
  20. long long i,primes_count = 0;
  21. start =( (long long*)param)[0];
  22. end  =( (long long*)param)[1];
  23. for(i = start ; i < end; i++)
  24. primes_count +=  isPrime(i);
  25. printf("Process %d Thread %u gets %lld primes from %lld to %lld\n",getpid(),(unsigned)pthread_self(),primes_count,start,end);
  26. pthread_exit(0);
  27. }
  28. int main()
  29. {
  30. pthread_t tid[10];
  31. pthread_attr_t attr;
  32. long long start_end[10][2];
  33. long long  i;
  34. for(i = 0; i < 10; i++)
  35. {
  36. start_end[i][0] = i*10000;
  37. start_end[i][1] = (i+1)*10000;
  38. pthread_attr_init(&attr);
  39. pthread_create(&tid[i],&attr,run,(void*)start_end[i]);
  40. }
  41. for(i= 0; i < 10; i++)
  42. pthread_join(tid[i],NULL);
  43. return 0;
  44. }

注意:使用pthread编译要加上-lpthread。 gcc -lm -lpthread example2.c

运行结果:(不是10^10,只计算到100000)

------------------------------------------------------------------------------------------------

遇到的问题:

最开始我的主函数写成这样:

  1. int main()
  2. {
  3. pthread_t tid[10];
  4. pthread_attr_t attr;
  5. long long start_end[2];
  6. long long i;
  7. for(i = 0; i < 10; i++)
  8. {
  9. start_end[0] = i*10000;
  10. start_end[1] = (i+1)*10000;
  11. pthread_attr_init(&attr);
  12. pthread_create(&tid[i],&attr,run,(void*)start_end);
  13. pthread_join(tid[i],NULL);
  14. }
  15. return 0;
  16. }

很明显pthread_join地方写错了,这样第一个进程运行完了才会创建第二个,但是由于每个线程平分,所以我没发现结果有异常。

写第三个程序时pthread_join也写错了位置,这才发现。但是我将pthread_join放到后面时,发现每个线程处理的数据段都是90000-100000,没找到原因,因此我的start_end改成了二维数组,这样各个线程就不会干扰了,具体的原因以后再研究。

--------------------------------------------------------------------------------------

这个程序应该比第一个快,但是判断第一段数据的线程使用的时间肯定没有最后一段使用的时间的千分之一,最后9个人看一个人干活,我突然想到了什么。。。

多线程方法2

多线程的目的就是压榨计算资源。我们可以使用下面的方法。

每个线程取一个数,然后判断,判断完了继续取下一个,让每个线程都不停的干活

线程取了1,判断,线程2取2判断,线程3取3,这时线程1干完了,接着取4,线程2又取5。。。。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <pthread.h>
  4. #include <sys/types.h>
  5. #include <unistd.h>
  6. #include <math.h>
  7. long long number = 1; //每个线程先取数,再把这个数加1
  8. long long isPrime(long long num)
  9. {
  10. long long i, s;
  11. s = (long long)sqrt((double)num);
  12. for(i = 2; i < s; i++)
  13. if(num % i == 0)
  14. return 0;
  15. return 1;
  16. }
  17. static pthread_mutex_t mutex;
  18. void * run(void * param)
  19. {
  20. long long primes_count=0;
  21. long long i = 1;
  22. while(i < 100000)
  23. {
  24. //要使用锁
  25. pthread_mutex_lock(&mutex);
  26. i = number;
  27. number ++;
  28. pthread_mutex_unlock(&mutex);
  29. primes_count +=  isPrime(i);
  30. }
  31. printf("Thread %u gets %lld primes\n",(unsigned  int)pthread_self(),primes_count);
  32. pthread_exit(0);
  33. }
  34. int main()
  35. {
  36. pthread_t tid[10];
  37. pthread_attr_t attr;
  38. pthread_mutex_init(&mutex,NULL);
  39. int i;
  40. for(i = 0; i < 10; i++)
  41. {
  42. pthread_attr_init(&attr);
  43. pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
  44. pthread_create(&tid[i],&attr,run,NULL);
  45. //pthread_join(tid[i],NULL); 一开始把join放这,结果只有第一个线程干活,找了好久才发现位置错了
  46. }
  47. for(i = 0; i < 10; i++)
  48. pthread_join(tid[i],NULL);
  49. return 0;
  50. }

运行结果:

多进程实现

用多线程能完成的,多进程也可以。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <pthread.h>
  4. #include <sys/types.h>
  5. #include <unistd.h>
  6. #include <math.h>
  7. #include <sys/ipc.h>
  8. #include <sys/shm.h>
  9. #include <errno.h>
  10. #include <string.h>
  11. long long isPrime(long long num)
  12. {
  13. long long i, s;
  14. s = (long long)sqrt((double)num);
  15. for(i = 2; i < s; i++)
  16. if(num % i == 0)
  17. return 0;
  18. return 1;
  19. }
  20. int main()
  21. {
  22. pid_t pid[10];
  23. int shmid;
  24. long long  i,primes_count=0;
  25. long long * addr;
  26. shmid = shmget(IPC_PRIVATE,4096,IPC_CREAT|0600);
  27. if(shmid < 0)
  28. {
  29. printf("get shared memory failed\n");
  30. exit(1);
  31. }
  32. addr = (long long*) shmat(shmid,0,0);
  33. *addr = 1;
  34. for(i = 0; i < 3; i++)
  35. fork();
  36. while(i < 100000)
  37. {
  38. i = (*addr);
  39. (*addr) ++;
  40. primes_count += isPrime(i);
  41. }
  42. printf("pid %d get %lld primes\n",getpid(),primes_count);
  43. return 0;
  44. }

注意:(1)使用循环fork,那么子进程还会fork,因此fork三次就得到了8个进程,在fork就16个进程了。要想产生10个进程,可以在主进程里写10个fork语句,还得写很多if(fork()==0)语句,懒得写,就直接用循环了。加上主进程一个8个,先生完了孩子再干活,生完之后都成了兄弟,一起干。

(2)这个程序有个严重的问题,使用了共享内存,但是没有使用同步机制,没有锁,挺麻烦的,不会用,就没写。结果可能不正确。

运行结果:

小结

我就截几个图

这是单线程的,CPU使用了100%,看来也不错,但是我的CPU有200%,有两个核(我用的虚拟机,可以分16个核哦亲),因此单线程不能充分利用计算资源。

多线程的把我的CPU都用完了。哈哈

多进程的呢?算一算,也是200%。

其实在Linux里面线程也是进程,称为LWP(Light Weighted Process),只不过在生成的时候参数不同。在以后的文章里会深入研究。

转载于:https://blog.51cto.com/nxlhero/1075979

多进程与多线程(1)相关推荐

  1. python廖雪峰_【Python】python中实现多进程与多线程

    进程与线程 进程(process)就是任务,是计算机系统进行资源分配和调度的基本单位[1].比如,打开一个word文件就是启动了一个word进程. 线程(thread)是进程内的子任务.比如word中 ...

  2. async python两个_【Python】python中实现多进程与多线程

    进程与线程 进程(process)就是任务,是计算机系统进行资源分配和调度的基本单位[1].比如,打开一个word文件就是启动了一个word进程. 线程(thread)是进程内的子任务.比如word中 ...

  3. 多进程和多线程的区别

    多线程和多进程的区别(重点 必须从cpu调度,上下文切换,数据共享,多核cup利用率,资源占用,等等各方面回答,然后有一个问题必须会被问到:哪些东西是一个线程私有的?答案中必须包含寄存器,否则悲催) ...

  4. gunicorn多进程不死_WEB,gunicorn - 无论是多进程、多线程、协程模式,同一个浏览器窗口多个标签页访问同一个url,看上去不会并发的问题...

    TL;DR 其实是浏览器同一个窗口下限制了对同一个url会执行串行操作. 1.参考 2.现象 我有一个WSGI APP,每次处理request都睡眠5秒.不管多进程.多线程.协程跑WSGI APP,同 ...

  5. 一文看懂Python多进程与多线程编程(工作学习面试必读)

    进程(process)和线程(thread)是非常抽象的概念, 也是程序员必需掌握的核心知识.多进程和多线程编程对于代码的并发执行,提升代码效率和缩短运行时间至关重要.小编我今天就来尝试下用一文总结下 ...

  6. 多进程与多线程的区别 - jihite

    多进程与多线程的区别 - jihite 时间 2014-03-16 10:16:00 博客园-所有随笔区 原文  http://www.cnblogs.com/kaituorensheng/p/360 ...

  7. GDB 调试多进程或者多线程应用

    GDB 是 linux 系统上常用的 c/c++ 调试工具, 功能十分强大. 对于较为复杂的系统, 比如多进程系统, 如何使用 GDB 调试呢? 考虑下面这个三进程系统 : 进程 ProcessChi ...

  8. python 多进程和多线程

    python 多进程和多线程 一.进程和线程 1.概念 进程: 一个进程就是一个任务,可以理解为一个程序.一个进程可以有多个线程,至少一个.多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影 ...

  9. 多线程处理同一批数据_多进程和多线程的优缺点

    来源:http://www.cnblogs.com/Yogurshine/p/3640206.html 在Linux下编程多用多进程编程少用多线程编程. IBM有个家伙做了个测试,发现切换线程cont ...

  10. php实现多进程、多线程

    孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程.孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作. 僵尸进程:一个进程使用f ...

最新文章

  1. FileInputStream、FileReader、FileWriter和File
  2. 怎么通过华为三层交换机实现VLAN间通信?
  3. java 写一个计算器_java编写一个计算器类
  4. 插件多行显示_Sublime Text 3最好的功能、插件和设置
  5. 城市轨道交通乘客信息系统的功能介绍
  6. Modbus 调试工具: Modbus poll与Modbus slave下载与使用(下)
  7. RK3288 开机时间和开机速度优化安卓系统优化
  8. P1957 口算练习题
  9. json 格式字符串
  10. 使用echarts中国地图上绘制散点图(自适应宽高)
  11. Redis 数据丢失问题排查
  12. Android kotlin let函数学习
  13. css单元格固定宽度大小,超过部分使用省略号表示
  14. 关于手册的页码和有效页清单 - LEP
  15. bi比较好的公司,bi商业智能软件排名
  16. 我的投资、理财、财富观
  17. HTML自动点名代码,js+html实现点名系统功能
  18. 软件工程应用与实践(1)——项目简介和小组分工
  19. Microbiome:微生物组名词定义
  20. 手把手教你学Python之Pandas(一文掌握数据分析与处理库-Pandas)

热门文章

  1. java中文件的操作讲解
  2. Linux 系统安装MySQL
  3. 没有实现类,MyBatis 的方法是怎么执行的?
  4. 在配置类上写@CompentScan注解来进行包扫描
  5. xml方式实现aop-快速入门
  6. 方法练习3_打印指定次数的HelloWorld
  7. 实现根据id查询房源数据的dubbo服务
  8. Stream流中的常用方法_map
  9. JAVA中ListIterator和Iterator详解与辨析
  10. 几个使用linux内核的系统,[科普] Linux 的内核与 Linux 系统之间的关系