Chinaunix首页 | 论坛 | 博客
  • 博客访问: 604574
  • 博文数量: 69
  • 博客积分: 2204
  • 博客等级: 大尉
  • 技术积分: 808
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-11 22:37
个人简介

..微笑着看着杯中的花茶一片片撑开.. ..透明的花瓣里水破开的声音很轻微..

文章分类

全部博文(69)

文章存档

2018年(1)

2017年(2)

2016年(10)

2015年(8)

2014年(6)

2013年(6)

2012年(4)

2011年(8)

2010年(12)

2009年(12)

分类:

2009-10-12 12:28:24

最近刚接触perl的多线程,由于以前一直是使用多进程,所以冷不防还不太适应。更加上让我遇到了一个比较头疼的问题后,才仔细的看了看perldoc。

我遇到的问题同这个老帖子中的很相像,因此把它也翻出来说说。


我想实现的是这样一个过程。在窗体下,一个按钮来控制一个while循环体,而退出完全由按钮来决定。

使用win32::GUI创建窗体

{
      添加按钮;
}

sub 按钮调用的函数
{
      获取按钮标签;

      如果按钮标签为ok->调用循环体;
      如果为停止->结束循环体;
}

sub 循环体
{
      这里可以是个死循环,也可以是个要运行较长时间的代码;
}

说到这里有个问题就是为什么不直接在按钮调用的函数里直接运行循环体,如果你试过应该知道,整个窗体应该处于一种假死状态,直到结束,当然,如果是个死循环就不用结束了。。。。 ;p

因此为了避免这种问题,一个解决办法就是再创建个线程让他自己跑去。因此上面代码应该为:

……
sub 按钮调用的函数
{
      获取按钮标签;

      如果按钮标签为ok -> 创建新线程$t1 -> 调用循环体;
      如果为停止->杀死$t1;
}
……

在老帖子里,flywind008曾经问为什么join不会结束线程;后来他换了detach后是真的正确了么?还有提到的threads->exit();在这里适用么?到底该怎么做呢?
先看下里面提到的几个方法。

->join();

它是指等待对应的线程运行完毕,当线程结束,然后返回参数或列表;如果你的thread是个死循环,那么它什么时候才会结束呢?至少它没有主动结束一个线程的作用;

原文:
This will wait for the corresponding thread to complete its execution. When the thread finishes,->join() will return the return value(s) of the entry point function.

->detach();

它是使线程处于非连接状态,并且丢弃掉任何返回的值,当程序运行结束时,被detach掉的线程还是会在终端里默默的运行的。。。。。。很显然,它只是放弃连接,但并不会终止掉那个你想终止的线程。在那个老帖子里,那个thread并没有被立刻终止,之所以楼主觉得终止了,大概是因为detach后一来没有返回值,二来他的程序在计数后last了循环。返回了。这时线程应该自己就结束了。因此并不是真正的被KILL了。

原文:
Makes the thread unjoinable, and causes any eventual return value to be discarded. When the program exits, any detached threads that are still running are silently terminated.


threads->exit();

再看看那个帖子中khandielas提到的threads->exit()。很好!这个方法的确可以立刻终止一个线程,但是只是终止当前的线程,如果你不小心结束了的是主线程,那么整个程序就都结束了。所以在用它终止线程前,你最好仔细检查下当前线程的ID是不是你要结束的线程。要查看ID的话,可以用tid();事实上,在我最早要做的那件事里,想要真正的结束我新创建的$t1,那么必须要在循环体里执行,当然我们可以设定一个哨兵变量,并用shared把它共享,然后在循环体里检查这个变量并按条件调用threads->exit()来结束这个线程。但是如果你的循环体循环一周要较长时间的话,这无疑仍旧会造成长时间不响应的情况发生。它依然不是我们最期望的。至少单独依靠它是不行的。

原文:If needed, a thread can be exited at any time by calling threads->exit(). This will cause the thread to return undef in a scalar context, or the empty list in a list context.
When called from the main thread, this behaves the same as exit(0).

->yield();

那个老帖子里没有提到yield。关于yield(),它主要是建议操作系统让当前的线程让出CPU给其它线程,至于执行的效果,很大程度上取决于你后面的线程的实现。。。。。很显然,只是让出,仍然不会结束。

原文:
This is a suggestion to the OS to let this thread yield CPU time to other threads. What actually happens is highly dependent upon the underlying thread implementation.

->kill();

这个才是我们在这里想要的,原帖中churchmice正确的回答了这个问题。但是它是如何实现的呢?它首先在你的子程序里加上一个KILL的信号,然后在要KILL它的时候根据信号来确定要KILL哪个sub。

原文:

    use threads;
    sub thr_func
    {
        # Thread 'cancellation' signal handler
        $SIG{'KILL'} = sub { threads->exit(); };
        ...
    }
    # Create a thread
    my $thr = threads->create('thr_func');
    ...
    # Signal the thread to terminate, and then detach
    # it so that it will get cleaned up automatically
    $thr->kill('KILL')->detach();

那么最初的那个程序里最终应该是这样的:

{
      添加按钮;
}

sub 按钮调用的函数
{
      获取按钮标签;

      如果按钮标签为ok -> 创建新线程$t1 -> 调用循环体;
      如果为停止->KILL掉$t1;
}
sub 循环体
{
      =>加入KILL的信号;
      这里可以是个死循环,也可以是个要运行较长时间的代码;
}

最后加个小例子,需要的模块:win32::GUI,Threads。

#!perl

#by banban;

use strict;
use warnings;
use Win32::GUI();
use Threads;
my $t1;
#生成主窗口;
my $main_window = new Win32::GUI::Window(
                  -name => "maiwindow",
                  -title => "test",
                  -pos => [400,400],
                  -size => [100, 100],
                  -resizable => 0
  ) or die "MainWindow $!";
  
#运行;
my $bt_do = $main_window->AddButton(
            -name => "bt_do",
            -text => "运行",
            -pos => [25,25],
            -size => [60, 20]
);
$main_window->Show();
Win32::GUI:ialog();
#########################################################################
sub Main_Terminate {
    -1; #terminate the message loop

}
#响应按钮事件;
sub bt_do_Click {
   
   my $value = $bt_do->Text();
      
   if($value eq '运行'){
     $bt_do->Text('停止');
     $t1 = threads->new (\&do);
     
   }else{
     $t1->kill('KILL')->detach();
      $bt_do->Text('运行');
   }
   
}


sub do
{
   $SIG{'KILL'} = sub { threads->exit(); };
   while(1)
   {
        print "I'm doing...\n";
        sleep (10); #这里代表要长时间运行的部分;

   }
}

 

(2009-10-12)

by banban

阅读(3038) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~