浅谈多线程编程

   为啥要搞多线程?因为多进程太耗费资源!一个进程包含(数据区,代码区,堆栈区)。而一个线程只有(堆栈区)。
    为啥要“多”xx程序设计!想想看,你用浏览器打开某一个网站的网页,可以这个网站的服务器坏了。如果你的浏览器是单线程的,你就得一直等待这个链接connect返回失败才能继续连接别的网页或者干其他的事情。 所以你可以为每一个连接创建一个线程,就算是打不开网页,你的主线程(WIN下面好像都是线程)或者主程序还可以干自己的事情。  
    多线程会不会提高程序效率?从上面的例子看是的!但是不要误解多线程的程序肯定就快!
    如果你的程序只是简单的递增一个简单的变量a的值,你创建10个线程分别递增a,和只是简单的一个主程序递增是没有区别的!多线程有可能会更慢,因为线程之间的调度会浪费时间。
    单核的CPU,是不是没必要写多线程程序?假设一个进程A一秒钟有1/5的时间是运行它。A创建多个线程并不会增加A进程的CPU运行时间。
    对于上面那个例子
         1  connect 服务器
         2  do something.
 如果是单线程的程序,那么程序就阻塞在1步骤上了,1/5的CPU时间就被浪费了一部分。
         如果多线程呢?
     像这样
          1 create threadconnect ;  
               2 do something;
          然后CPU分别执行 do something 和 threadconnect。由于CPU是单核的,所以不存在并行执行,他们两个操作本来是要均分1/5的CPU时间的(看OS具体实现了)。但是由于threadconnect被阻塞,该线程会睡眠,所以CPU会尽量多运行 do something。这个时候,你不用等待threadconnect完成就可以干自己的事情。等connect返回后,这两个线程又会均分进程空间的时间了。但是你的程序没有空转,所以效率高了!
         单线程当然也可以达到多线程的效果
    比如还是那个例子:
             while(true)
           {
               1  connect;
               2  do something;
           }
         这里第一步的区别是 不等待connect的返回,直接执行第二步,然后每次用while来查看connect有没有连接好,如果没连接好,继续做自己的事情。程序也没有空转。就是选择非阻塞IO。具体的程序设计起来会更复杂,这里只是为了说明道理!
     多线程编程的另一个难点是 对全局资源的使用。
      例如一个全局变量 a, 有一个线程A对a加1,一个线程B对a减2。
   如下:
      A线程: a+=1;                B线程: a-=2;
  等价       1 mov ax,a            等价     1 mov ax,a
               2 add ax,1                        2 sub  ax,2
               3 mov a,ax                       3 mov a,ax
  假设 a=2一开始。
      线程A运行完2时,切换到了B线程.此时B线程操作的数据还是内存中的a=2.然后等B线程运行完,a=0,切换到A,然后把ax中的3放入内存中的变量a中。这样就把B线程的结果给覆盖掉了。看来这样不加以限制 A,B线程,会导致很严重的后果---程序结果就变得不确定了。
      最好的方法就是 加锁 LOCK;
程序变成这样
      A线程 : LOCK                B线程  LOCK
                        a+=1;                          a-=2;
                       UNLOCK                      UNLOCK
这样 a+=1和 a-=2就变成 原子操作=》不可分割的操作
就算是 A线程在运行完 add ax,1后 切换到 B线程,但是由于 A已经LOCK了,所以B线程只能干等!然后程序又切换到A线程,A线程得以运行完!
          a+=1;a-=2; 这两行代码 又叫做 临界区
看来线程对 临界区的操作 要LOCK(其实就是修改全局变量就LOCK)。
       看来多线程编程相当简单了。
举个例子:  全局变量  List a;         有两个操作 addnode(list& a)  delnode(list& a)
                 main()
             {
                   
               create  ThreadA=FUNCITON1;
               create  ThreadB=FUNCITON2;    
             }  
FUNCITON1                  FUNCTION2
{                                 {    
    LOCK;                         LOCK;
    addnode(a);                delnode(a);
    UNLOCK;                     UNLOCK;
}                                 }
以上就是多线程编程的模板,不管是UNIX还是WIN下 都一样。
     还有一个问题 LOCK是什么?看看0.12Linux Kernel怎么写的吧
     void lock()                    void unlock()
       {                                 {        
           cli()关中断;                     cli() 关中断;
           while(lock==1)               lock=0;
               sleep();                     wake(lock);
           lock=1;                         sti() 开中断;
           sti()开中断;                }
       }
为什么要 开关中断? 很明显为了上面叙述过的 原子操作!
为啥要sleep和wake;
      如果一个线程A得不到 LOCK 还一味的试探 lock是否为0,那么程序会空转!如果A睡觉,那么A的时间会让给其他线程,如B。
    为啥要wake? A已经睡觉了,贡献了自己的运行时间,B运行完得唤醒我,让我运行啊!来而不往非礼也! 这个职业的说法叫 信号量 (应该说是原理,提出者是狄伊克斯特拉,是个应该被大家记住的名字)
    现在时多核时代!!!简单的开关中断显然不行。因为运行在其他核心的线程B,仍然有可能进入临界区!
    看来需要寻求硬件的帮助了!
好吧   TSL  指令发明出来了。  
       TSL  寄存器register,锁lock
 原理: TSL指令 把内存中的LOCK值读取到寄存器register中,然后在内存中的LOCK中存一个非0值。这两个操作很明显要 原子操作。
       执行TSL指令的CPU会锁住内存总线,以禁止其他CPU在本指令结束之前访问内存。
 改写新的LOCK
        LOCK:
              TSL register,lock
              cmp register ,0   //如果lock为0的话,就取得了锁,然后RET返回。反之则忙
              jne   enter_region//等待,这里可以换成call otherfunction 以避免忙等待
              ret
         UNLOCK:
               mov lock,0
               ret
锁的问题看来搞的差不多了。
以上的内容超出了 多线程编程的 内容,多线程编程只需要套模板,当然API有很多。但是掌握了这些理论知识。通吃你多线程还是多进程。 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值