线程待返回值等问题

问题一,线程的基本操作,例如:暂停、继续、停止等

我不建议使用Thread类提供的Suspend、Resume以及Abort这三个方法,前两个有问题,好像在VS05已经屏蔽这两个方法;对于Abort来说,除了资源没有得到及时释放外,有时候会出现异常。如何做呢,通过设置开关变量来完成

问题二,如何向线程传递参数或者从中得到其返回值;

 我不建议使用静态成员来完成,仅仅为了线程而破坏类的封装有些得不偿失。那如何做呢,通过创建单独的线程类来完成

        //委托
        public delegate double weiTuo(double a, double b);
        weiTuo w;

        private void btn_Begin_Click(object sender, EventArgs e)
        {
            //Thread th_thread = new Thread();
            w = new weiTuo(getCount);
            //异步调用中的参数和返回值
            AsyncCallback callback = new AsyncCallback(AsyncCallbackImpl);
            w.BeginInvoke(1, 2, callback, null);

        }
        //线程调用的方法
        double getCount(double a, double b)
        {
            return a + b;
        }
        /// <summary>
        /// 线程完成之后回调的函数
        /// </summary>
        /// <param name="ar"></param>
        public void AsyncCallbackImpl(IAsyncResult ar)
        {
            //获取执行完后的返回值
            double re = w.EndInvoke(ar);
            MessageBox.Show(" " + ar.AsyncState);
        }

Code

当线程的ThreadState==ThreadState.Stop时,一般就说明线程完成了工作,这时结果就可用了,如果不是这个状态,就继续执行别的工作,或者等待一会,然后再尝试.倘若需要等有多个子线程需的返回,并且需要用他们的结果来进行进异步计算,那就叫做线程同步了,下面我们介绍另外一种我比较推荐的方法,能够自定义参数个数,并且返回数据,而且使用起来也相对方便

使用委托的异步调用方法和回调

首先我们要把需要异步调用的方法定义为一个委托,然后利用BeginInvoke来异步调用,BeginInvoke的第一个参数就是直径,第二个是当线程执行完毕后的调用的方法

问题三,如何使线程所占用的CPU不要老是百分之百

造成这个原因是由于线程中进行不间断的循环操作,从而使CPU完全被子线程占有。那么处理此类问题,其实很简单,在适当的位置调用Thread.Sleep(20)来释放所占有CPU资源,不要小看这20毫秒的睡眠,它的作用可是巨大的,可以使其他线程得到CPU资源,从而使你的CPU使用效率降下来。

对于上面三个问题用一个例子呈现给大家:

namespace ThreadTemplate
{
    using System;
    using System.Threading;
    using System.IO;
    /// <summary>
    /// Summary description for clsSubThread.
    /// </summary>
    public class clsSubThread:IDisposable
    {
        private Thread thdSubThread = null;
        private Mutex mUnique = new Mutex();

        private bool blnIsStopped;
        private bool blnSuspended;
        private bool blnStarted;
        private int nStartNum;

        public bool IsStopped
        {
            get{ return blnIsStopped; }
        }
        public bool IsSuspended
        {
            get{ return blnSuspended; }
        }
        public int ReturnValue
        {
            get{ return nStartNum;}
        }

        public clsSubThread( int StartNum )
        {
            //
            // TODO: Add constructor logic here
            //
            blnIsStopped = true;
            blnSuspended = false;
            blnStarted = false;

            nStartNum = StartNum;
        }

        /// <summary>
        /// Start sub-thread
        /// </summary>
        public void Start()
        {
            if( !blnStarted )
            {
                thdSubThread = new Thread( new ThreadStart( SubThread ) );
                blnIsStopped = false;
                blnStarted = true;
                thdSubThread.Start();
            }
        }

        /// <summary>
        /// Thread entry function
        /// </summary>
        private void SubThread()
        {
            do
            {
                // Wait for resume-command if got suspend-command here
                mUnique.WaitOne();
                mUnique.ReleaseMutex();

                nStartNum++;

                Thread.Sleep(1000); // Release CPU here
            }while( blnIsStopped == false );
        }

        /// <summary>
        /// Suspend sub-thread
        /// </summary>
        public void Suspend()
        {
            if( blnStarted && !blnSuspended )
            {
                blnSuspended = true;
                mUnique.WaitOne();
            }
        }

        /// <summary>
        /// Resume sub-thread
        /// </summary>
        public void Resume()
        {
            if( blnStarted && blnSuspended )
            {
                blnSuspended = false;
                mUnique.ReleaseMutex();
            }
        }

        /// <summary>
        /// Stop sub-thread
        /// </summary>
        public void Stop()
        {
            if( blnStarted )
            {
                if( blnSuspended )
                    Resume();

                blnStarted = false;
                blnIsStopped = true;
                thdSubThread.Join();
            }
        }
        #region IDisposable Members
        /// <summary>
        /// Class resources dispose here
        /// </summary>
        public void Dispose()
        {
            // TODO:  Add clsSubThread.Dispose implementation
            Stop();//Stop thread first
            GC.SuppressFinalize( this );
        }

        #endregion
    }
}

那么对于调用呢,就非常简单了,如下:

        // Create new sub-thread object with parameters
        clsSubThread mySubThread = new clsSubThread( 5 );

        mySubThread.Start();//Start thread

        Thread.Sleep( 2000 );
        mySubThread.Suspend();//Suspend thread 

        Thread.Sleep( 2000 );
        mySubThread.Resume();//Resume thread 

        Thread.Sleep( 2000 );
        mySubThread.Stop();//Stop thread 

        //Get thread‘s return value
        Debug.WriteLine( mySubThread.ReturnValue );

        //Release sub-thread object
        mySubThread.Dispose();

Code

在回过头来看看前面所说的三个问题。

对于问题一来说,首先需要局部成员的支持,那么

private Mutex mUnique = new Mutex();
        private bool blnIsStopped;
        private bool blnSuspended;
        private bool blnStarted;

Code

光看成员名称,估计大家都已经猜出其代表的意思。接下来需要修改线程入口函数,要是这些开关变量能发挥作用,那么看看SubThread这个函数。

/// <summary>
        /// Thread entry function
        /// </summary>
        private void SubThread()
        {
            do
            {
                // Wait for resume-command if got suspend-command here
                mUnique.WaitOne();
                mUnique.ReleaseMutex();

                nStartNum++;

                Thread.Sleep(1000);
            }while( blnIsStopped == false );
        }

Code

函数比较简单,不到十句,可能对于“blnIsStopped == false”这个判断来说,大家还比较好理解,这是一个普通的判断,如果当前Stop开关打开了,就停止循环;否则一直循环。

大家比较迷惑的可能是如下这两句:

mUnique.WaitOne();

mUnique.ReleaseMutex();

这两句的目的是为了使线程在Suspend操作的时候能发挥效果,为了解释这两句,需要结合Suspend和Resume这两个方法,它俩的代码如下。

/// <summary>
        /// Suspend sub-thread
        /// </summary>
        public void Suspend()
        {
            if( blnStarted && !blnSuspended )
            {
                blnSuspended = true;
                mUnique.WaitOne();
            }
        }

        /// <summary>
        /// Resume sub-thread
        /// </summary>
        public void Resume()
        {
            if( blnStarted && blnSuspended )
            {
                blnSuspended = false;
                mUnique.ReleaseMutex();
            }
        }

Code

为了更好地说明,还需要先简单说说Mutex类型。对于此类型对象,当调用对象的WaitOne之后,如果此时没有其他线程对它使用的时候,就立刻获得信号量,继续执行代码;当再调用ReleaseMutex之前,如果再调用对象的WaitOne方法,就会一直等待,直到获得信号量的调用ReleaseMutex来进行释放。这就好比卫生间的使用,如果没有人使用则可以直接使用,否则只有等待。

明白了这一点后,再来解释这两句所能出现的现象。

mUnique.WaitOne();

mUnique.ReleaseMutex();

当在线程函数中,执行到“mUnique.WaitOne();”这一句的时候,如果此时外界没有发送Suspend消息,也就是信号量没有被占用,那么这一句可以立刻返回。那么为什么要紧接着释放呢,因为不能总占着信号量,立即释放信号量是避免在发送Suspend命令的时候出现等待;如果此时外界已经发送了Suspend消息,也就是说信号量已经被占用,此时“mUnique.WaitOne();”不能立刻返回,需要等到信号量被释放才能继续进行,也就是需要调用Resume的时候,“mUnique.WaitOne();”才能获得信号量进行继续执行。这样才能达到真正意义上的Suspend和Resume。

现在再来分析一下问题二,其实例子比较明显,是通过构造函数和属性来完成参数和返回值,这一点我也不多说了。如果线程参数比较多的话,可以考虑属性来完成,类似于返回值。

问题三,我就更不用多说了。有人说了,如果子线程中的循环不能睡眠怎么办,因为睡眠的话,有时会造成数据丢失,这方面的可以借鉴前面Suspend的做法,

为什么不能直接在子线程中操纵UI呢。原因在于子线程和UI线程属于不同的上下文,换句比较通俗的话说,就好比两个人在不同的房间里一样,那么要你直接操作另一个房间里的东西,恐怕不行罢,那么对于子线程来说也一样,不能直接操作UI线程中的对象。

那么如何在子线程中操纵UI线程中的对象呢,.Net提供了Invoke和BeginInvoke这两种方法。简单地说,就是子线程发消息让UI线程来完成相应的操作

这两个方法有什么区别,这在我以前的文章已经说过了,Invoke需要等到所调函数的返回,而BeginInvoke则不需要。

用这两个方法需要注意的,有如下三点:

第一个是由于Invoke和BeginInvoke属于Control类型的成员方法,因此调用的时候,需要得到Control类型的对象才能触发,也就是说你要触发窗体做什么操作或者窗体上某个控件做什么操作,需要把窗体对象或者控件对象传递到线程中。

第二个,对于Invoke和BeginInvoke接受的参数属于一个delegate类型,我在以前的文章中使用的是MethodInvoker,这是.Net自带的一个delegate类型,而并不意味着在使用Invoke或者BeginInvoke的时候只能用它。参看我给的第二篇文章(《如何弹出一个模式窗口来显示进度条》),会有很多不同的delegate定义。

最后一个,使用Invoke和BeginInvoke有个需要注意的,就是当子线程在Form_Load开启的时候,会遇到异常,这是因为触发Invoke的对象还没有完全初始化完毕。处理此类问题,在开启线程之前显式的调用“this.Show();”,来使窗体显示在线程开启之前。如果此时只是开启线程来初始化显示数据,那我建议你不要使用子线程,用Splash窗体的效果可能更好。

时间: 2024-11-08 04:00:43

线程待返回值等问题的相关文章

在Java 线程中返回值的用法

http://icgemu.iteye.com/blog/467848 在Java 线程中返回值的用法 博客分类: Java Javathread 有时在执行线程中需要在线程中返回一个值:常规中我们会用Runnable接口和Thread类设置一个变量:在run()中改变变量的值,再用一个get方法取得该值,但是run何时完成是未知的:我们需要一定的机制来保证. 在在Java se5有个Callable接口:我们可以用该接口来完成该功能: 代码如: Java代码   package com.thr

线程的返回值

线程的返回值当线程退出时,线程可以选择向主线程返回一个值,返回方式一共有4种1\如果要返回int类型,可以使用pthread_exit((int)* return_value);2\使用全局变量返回(这个最简单)3\使用malloc所分配的空间4\直接返回字符串,如pthread_exit("return value"); #include <stdio.h> #include <stdlib.h> #include <string.h> #incl

python多线程获取子线程任务返回值

今天想实现多线程更新资产信息,所以使用到了threading,但是我需要每个线程的返回值,这就需要我在threading.Thread的基础上进行封装 def auto_asset(node): ret = salt.remote_grains_execution_sigle(node) asset_info={} asset_info['os']= ret[node]['oscodename'] asset_info['kernelrelease']= ret[node]['kernelrel

Java多线程——&lt;三&gt;让线程有返回值

一.概述 到目前为止,我们已经能够声明并使一个线程任务运行起来了.但是遇到一个问题:现在定义的任务都没有任何返回值,那么加入我们希望一个任务运行结束后告诉我一个结果,该结果表名任务执行成功或失败,此时该怎么办呢? 答案是使用Callable.之前定义的任务都直接实现了Runnable,该接口的run方法并无返回值.而Callable的call方法可以根据你传入的泛型参数返回对应类型的数据. 二.实现 1.实现Callable接口,定义可返回结果的线程任务 public class TaskCal

java线程池的自带监控,线程池返回值的控制

当使用java线程池的时候,返回值类型用future<T> 来接收,比如: Future<String> future = fixedThreadPool.submit(new Thread());返回的结果必须由线程执行完毕后才会返回,我们可以利用这一点进行线程堵塞,监控线程的结束时间. package com.test; import java.util.ArrayList; import java.util.List; import java.util.concurrent.

Java多线程——&lt;四&gt;让线程有返回值

一.概述 到目前为止,我们已经能够声明并使一个线程任务运行起来了.但是遇到一个问题:现在定义的任务都没有任何返回值,那么加入我们希望一个任务运行结束后告诉我一个结果,该结果表名任务执行成功或失败,此时该怎么办呢? 答案是使用Callable.之前定义的任务都直接实现了Runnable,该接口的run方法并无返回值.而Callable的call方法可以根据你传入的泛型参数返回对应类型的数据. 二.实现 1.实现Callable接口,定义可返回结果的线程任务 public class TaskCal

如何实现处理线程的返回值

方法有以下几种: 主线程等待法 使用Thread类的join()阻塞当前线程以等待子线程处理完毕 通过Callable接口实现: 通过FutureTask Or线程池获取 一.主线程等待法 如下代码 public class CycleWait implements Runnable { private String name; @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedExceptio

Java线程池,获取返回值

程序中使用的是Callable接口,可以获取线程的返回值. package liuzh; import java.util.LinkedList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.Lin

java线程返回值讨论

java线程返回值讨论在线程当中,返回值是个很大的问题.比如:在线程执行到某一步的时候要将数据返回,在程序执行完成后要返回值.在java中,线程的返回值可以使用Future<T>来获取,也可以使用其他的手段.以下讨论一些返回值的一些小手段:1.使用静态变量来进行值的返回使用静态变量来进行值的返回是最简单的一种,也是不可取的一种,这种不仅带来线程的安全性,同时内存一直不能释放,直到系统退出才能释放内存,因此会造成内存花费很多,但是真正在使用的很少.2.使用Futuren<T>来获取这