LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 6143|回复: 14

shell能否实现多线程编程?

 关闭 [复制链接]
发表于 2004-4-5 17:12:53 | 显示全部楼层 |阅读模式
shell能否实现多线程编程?比如说我在执行某程序的编译安装(此过程将耗时较长)时,希望可以同时去执行另外一个程序,成功后返回。如果能实现,具体该怎么做?我已经搜索了,很抱歉没找到想关主题。Thank you!
发表于 2004-4-5 17:44:13 | 显示全部楼层
当然可以。Bash有"协同进程"这个概念。
以下程序就是把每个解压缩进程放到后台,然后用wait语句等待每个进程的结束。

  1. #!/bin/sh
  2. for arch in $(ls | egrep '*.tar.[bg]z(2|)'); do
  3.       case ${arch##*.} in
  4.                bz2) tar jxf $arch -C /tmp & ;;
  5.                *) tar zxf  $arch -C /tmp & ;;
  6.       esac   
  7. done
  8. wait
复制代码

要注意两点:
1. 对超线程芯片或smp架构的机子,"协同进程"的优势才能得到最大程度的体现。
2. 避免每个后台进程都竞争同一个系统资源,这样会出现"系统颠簸"的现象,反而影响了效率。

请参见:
http://www.linuxsir.cn/forum.php?mod=viewthread&tid=98313
发表于 2004-4-6 08:03:25 | 显示全部楼层
还是不明白,大家用的究竟是多进程还是多线程?
发表于 2004-4-6 09:12:56 | 显示全部楼层
"多线程"这个概念,Linux还远远没有完善吧。反而"多进程"很成熟,也很高效。
 楼主| 发表于 2004-4-6 10:47:13 | 显示全部楼层
>>多谢版主指导,您的方法我也想过,其实这严格来说并非多线程(是否可以这么说?:p).倒很象多进程。转入后台的方法有些时候可能会使程序执行的更慢吧?因为我想后台程序的优先级可能会低些,不知道是不是这样?我想过通过trap来定时捕获系统信号,让两个进程分时进行调度,但这样系统开销未免太大,也并非严格意义上的多线程,如果实现也只是多程序的并发执行而已。所以我想Shell编程是无法实现多线程的,这里说的仅仅是shell,并非说Linux无法实现多线程,在Linux下,C++或者Java都可以很容易实现多线程,是这样的吧.
发表于 2004-4-6 11:07:29 | 显示全部楼层
其实这严格来说并非多线程(是否可以这么说?:p).倒很象多进程。

没错,这只是多进程,就是bash的协同进程。
转入后台的方法有些时候可能会使程序执行的更慢吧?因为我想后台程序的优先级可能会低些,不知道是不是这样?我想过通过trap来定时捕获系统信号,让两个进程分时进行调度,但这样系统开销未免太大,也并非严格意义上的多线程,如果实现也只是多程序的并发执行而已。

没错,后台进程的资源优先级默认比前台进程低,不过,手动顺序执行多个进程所耗费的中间时间更值得注意。
所以我想Shell编程是无法实现多线程的,这里说的仅仅是shell,并非说Linux无法实现多线程,在Linux下,C++或者Java都可以很容易实现多线程,是这样的吧.

注意,线程是进程的多个实例,也就是说,无论多少个线程,它们都包含在进程里,受进程所管制。而在UNIX家族里,一个进程就是一个程序(命令)的运行时,shell的任务是用来管理进程而不是线程的,管理线程是进程本身的任务,也就是编写命令的C程序员的任务。不应该越俎待庖。
 楼主| 发表于 2004-4-6 11:20:10 | 显示全部楼层
最初由 home_king 发表


而在UNIX家族里,一个进程就是一个程序(命令)的运行时,shell的任务是用来管理进程而不是线程的,管理线程是进程本身的任务,也就是编写命令的C程序员的任务。不应该越俎待庖。


>>我想你该说在OS家族里,这样会准确些。
>>shell脚本里面可以通过trap来使用系统调用或者自设程序来实现多进程的切换,不一定就的by hand.
>>shell任务是来管理进程的,这个说法在shell无法实现多线程时,我比较赞同。
>>管理线程是进程本身的任务,也就是编写命令的C程序员的任务。不应该越俎待庖。
对此本人不敢苟同,你的意思是说我们无法直接管理和控制线程。我想这个说法是错误的。程序员可以在程序里面直接对线程的操作进行控制和处理,难道不可以吗?
本人才疏学浅,还望版主详细阐述此问题.
发表于 2004-4-6 11:49:15 | 显示全部楼层
>>我想你该说在OS家族里,这样会准确些。

UNIX是一个很棒的多任务操作系统。"命令"这个概念在其他操作系统不常用,呵呵。

>>shell脚本里面可以通过trap来使用系统调用或者自设程序来实现多进程的切换,不一定就的by hand.

trap并不是系统调用,而是"信号"触发器。信号来临后,通常调用自己的函数来处理。
trap handler SIGNAL

>>管理线程是进程本身的任务,也就是编写命令的C程序员的任务。不应该越俎待庖。
对此本人不敢苟同,你的意思是说我们无法直接管理和控制线程。我想这个说法是错误的。程序员可以在程序里面直接对线程的操作进行控制和处理,难道不可以吗?

呵呵,楼顶帖子斑竹提及,"执行某程序的编译安装(此过程将耗时较长)时,希望可以同时去执行另外一个程序,成功后返回",试想有这样奇怪的进程吗?

线程是进程的内部实例,它由进程的静态时(程序)的内容所决定,然后调用内核或者glibc的线程库来创建线程,并不需要人工干预,因为这是无法想象的(线程的协作复杂度甚于进程),更是无意义的(要操作线程还不如操作进程,因为我们每键入一个命令就创建一个进程)。
我的看法是,进程是面向用户的,线程是面向进程本身的。

由于历史缘故,UNIX的多进程机制比多线程机制更完善。
如果是脚本来实现多进程,ksh就有很好的协进程特色。斑竹看看无妨。
发表于 2004-4-6 13:11:50 | 显示全部楼层

看了半天,有点迷糊了

线程和进程的区别是这样的吗?
进程:一个程序在多的内存空间里面运行,相互独立。
线程:多个程序在一个内存空间里面运行,共享数据空间。
而我的认为是:shell的运行一定是进程,而不是线程,线程的实现好象比较复杂,在一些内存共享的空间里面,对数据的锁定什么的很久了,都明白不了。]
有谁能给讲一些线程和进程的区别吗?
 楼主| 发表于 2004-4-6 14:26:48 | 显示全部楼层
trap并不是系统调用,而是"信号"触发器。信号来临后,通常调用自己的函数来处理。
trap handler SIGNAL

>>我想你误解我的意思了,我说的系统调用当然不指trap,而是把上面的handler设置为系统调用,有何疑义吗?

呵呵,楼顶帖子斑竹提及,"执行某程序的编译安装(此过程将耗时较长)时,希望可以同时去执行另外一个程序,成功后返回",试想有这样奇怪的进程吗?

难道真的没有吗?举个简单类似的例子,比如我们在浏览网页的时候,网页上除了基本的html文本外还有大量的比如图象,视频文件。那么我们打开网页的时候,并不时让网页从上而下显示,而是将文本与其他媒体(这里是图象和视频)分几个线程同时下载,所以我们往往看到文本先显示,但当所有的东西都显示完后,浏览器状态才显示100%,即标志此进程已完成。不知道此例有无不妥,有请指出。
线程是进程的内部实例,它由进程的静态时(程序)的内容所决定,然后调用内核或者glibc的线程库来创建线程,并不需要人工干预,因为这是无法想象的(线程的协作复杂度甚于进程),更是无意义的(要操作线程还不如操作进程,因为我们每键入一个命令就创建一个进程)。
我的看法是,进程是面向用户的,线程是面向进程本身的。


你所说的过于片面,线程是进程的内部实例,这句话很大程度上是错误的。在多线程OS中,进程只作为系统资源分配的单位,给线程提供资源而已,并不是一个可执行的实体,而真正的可执行实体却是线程。你说的“人工干预”不知为何意?难道人没办法控制线程吗?难道线程的控制真的就那么的困难吗?那么请看下面的线程控制的实例:

  1. #include <pthread.h>
  2. #include <stdio.h>

  3. int sum;
  4. void *runner(void *param);

  5. main(int argc,char *argv[])
  6. {
  7.   pthread_t tid;
  8.   pthread_attr_t attr;
  9.   if(argc !=2){
  10.    fprintf(stderr,"usage:a.out<integer value>\n");
  11.    eixt();
  12.   }
  13.   if(atoi(argv[1])<0){
  14.    fprintf(stderr,"%d must be <=0\n",atoi(argv[1]));
  15.    exit();
  16.   }
  17. pthread_attr_init(&attr);
  18. pthread_create(&tid,&attr,runner,argv[1]);
  19. pthread_join(tid,NULL);
  20. printf("sum=%d\n",sum);
  21. }

  22. void *runner(void *param);
  23. {
  24.  int i;
  25.  sum=0;
  26.  if (upper>0){
  27.     for(i=1;i<=upper;i++)
  28.       sum+=i;
  29.   }
  30. pthread_exit(0);
  31. }
复制代码

以上程序轻松的实现了线程的创建、以及执行、退出。为何不能?



由于历史缘故,UNIX的多进程机制比多线程机制更完善。

Unix并无多线程机制!
#####以下引用王波--<<FreeBSD使用大全>>#####
在Unix中,是使用的进程概念来区分不同的独立计算任务,进程具有独立的上下文空间、独立数据空间等等特性,这样进程就可以很容易的独立执行,内核就可以根据优先级在进程之间进行切换,因此进程也就是最基本的内核调度实体。但是,由于计算任务的复杂性,很多任务需要使用多个进程完成,而且这些进程之间需要交换数据。为了解决这个问题,Unix中又设计了多种进程间的通信方式,称为IPC,例如管道、共享内存、套接字等等,这些内容本身就可以独立使用一本专门的书籍来描述了。

因此对于一些比较复杂的程序,就形成了一个怪圈,为了隔离计算任务,设计了进程的概念,为了进程之间能够共享数据,又设计了多种IPC通信方式。因此,人们就希望能设计一种能够独立执行,但没有独立数据空间的轻量级进程的概念,这就是线程。

明显的,线程对于复杂系统来讲非常有意义,因为不再需要复杂的IPC通信方式维护进程之间的数据交换,同时多个线程也可以独立、并行的执行。目前,很多数据库系统、Java应用程序都需要线程支持。但是由于Unix系统本身并不存在线程这个概念,那么在Unix下引入线程就有两种比较直接的方式。

第一种方式是不在内核中实现线程,而在用户程序本身中实现线程,这实际是对线程的一种模拟,线程之间的切换和调度是在用户的进程内部进行的,这种方式就被称为用户空间的线程。这种线程的好处是实现非常简单,而且性能也非常好,因为线程之间的切换都在用户进程内部进行,切换开销比较小。FreeBSD下缺省就使用这种线程模式。

它的缺点也很明显,首先就是不能充分利用高端服务器系统的SMP多处理器的优点,因为一个进程只能由一个处理器处理,第二点由于用户空间线程是在用户空间切换,某个线程遇到一个需要阻塞的系统调用而就会造成整个进程被阻塞,因而其他线程也被阻塞,这中情况实际在线程的概念中是不允许的,但实际实现中很难被百分之百避免。

第二种实现方式是通过修改进程的实现方式来完成,可以使用不完全的进程创建方式创建共享数据空间的进程,在Linux下这种系统调用为clone(),而在FreeBSD下它为rfork()。这种方式是Linux的基本线程处理方式,FreeBSD下可以使用linuxthread的兼容库来实现这种线程。
#####引用结束!


严格来说,Linux也没有真正的多线程
Linux的线程实现无非就是通过fork()或者clone()系统调用来实现的。fork()的仅仅是实现进程的复制,把父进程中的所有数据结构复制到新进程中而已,并没有产生线程!clone()也只不过实现了进程的复制而已,但它复制的新进程(即我们认为的线程)中的数据区只是一个指向父进程中数据区的指针而已!所以在Linux下实际上就没有线程的概念!真正实现线程的是WinNT/2000或者Solaris这些!它们本身就是以线程为基础进行任务调度的,性能较好比较正常。SUN Solaris的线程实现则提供了另一个很好的参考平台,在Solaris中,事实上是混用了用户空间的线程和进程基础的线程的,使用多个进程运行更多的线程,因此可以综合利用多处理器的优点和在进程内部切换线程的优点。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表