c# ProgressBar

1.使用PictureBox加载一个gif图像,这样的好处是可以避免winform中的线程的困扰。下面就是这个所使用的图片资源。比较容易。如果想要使用progress bar的话,直接设置PictureBox的visible属性

http://cid-f41b44b9285d0b86.spaces.live.com/blog/cns!F41B44B9285D0B86!298.entry中存在这个资源。

2.使用.net中的ProgressBar控件

http://blog.csdn.net/gisfarmer/archive/2009/01/12/3757595.aspx

第一步:设计界面不说了...注意需要引用 using System.Threading;
第二步:定义一个代理,用于更新ProgressBar的值(Value)

  1. //更新进度列表
  2. private delegate void SetPos(int ipos);

第三步:进度条值更新函数(参数必须跟声明的代理参数一样)

  1. private void SetTextMessage(int ipos)
  2.         {
  3. if (this.InvokeRequired)
  4.             {
  5.                 SetPos setpos = new SetPos(SetTextMessage);
  6. this.Invoke(setpos, new object[] { ipos});
  7.             }
  8. else
  9.             {
  10. this.label1.Text = ipos.ToString() + "/100";
  11. this.progressBar1.Value = Convert.ToInt32(ipos);
  12.             }
  13.         }

第四步:函数实现

  1. private void button1_Click(object sender, EventArgs e)
  2.         {
  3.             Thread fThread = new Thread(new ThreadStart(SleepT));//开辟一个新的线程
  4.             fThread.Start();
  5.         }

第五步:新的线程执行函数:

  1. private void SleepT()
  2.         {
  3. for (int i = 0; i < 500; i++)
  4.             {
  5.                 System.Threading.Thread.Sleep(100);//没什么意思,单纯的执行延时
  6.                 SetTextMessage(100 * i / 500);
  7.             }
  8.         }

上面涉及到了c#线程的知识,。

在c#中,线程的基础知识。

1.如何创建线程

c#中最简单的创建线程的方法是定义一个Delegate。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;

namespace CSharpThread
{
    class Program
    {
        static int TaskAWhile (int data, int ms)
        {
            Console.WriteLine("TaskAWhile begins...");
            Thread.Sleep(ms);
            Console.WriteLine("TaskAWhile ends...");

            return data++;
        }

/* 定义delegate类型 */

        public delegate int TaskAWhileDelegate(int data, int ms);

        static void Main(string[] args)
        {
            TaskAWhileDelegate dl = TaskAWhile;

/* BeginInvoke方法的返回类型IAsyncResult,在该返回类型中可以验证委托是否完成了任务 */
IAsyncResult ar = dl.BeginInvoke(1, 3000, null, null);

            while ( !ar.IsCompleted )
            {
                Console.Write(".");
                Thread.Sleep(50);
            }   // ends while

/* EndInvoke方法会等待委托进程最终完成 */

            int result = dl.EndInvoke(ar);

            Console.WriteLine("Result is {0}", result);

        }
    }
}

同时还能定义当委托事件完成之后,调用的函数。example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;

namespace CSharpThread
{
    class Program
    {
        static int TaskAWhile (int data, int ms)
        {
            Console.WriteLine("TaskAWhile begins...");
            Thread.Sleep(ms);
            Console.WriteLine("TaskAWhile ends...");

            return data++;
        }

        public delegate int TaskAWhileDelegate(int data, int ms);

        static void TaskAWhileCompleted (IAsyncResult ar)
        {
            if (ar == null)
                throw new ArgumentNullException("ar");

            TaskAWhileDelegate dl = ar.AsyncState as TaskAWhileDelegate;
            int result = dl.EndInvoke(ar);
            Console.WriteLine("flag");
            Console.WriteLine("result : {0}", result);
        }

        static void Main(string[] args)
        {
            TaskAWhileDelegate dl = TaskAWhile;
            IAsyncResult ar = dl.BeginInvoke(1, 3000, TaskAWhileCompleted, dl);

            for (int i = 0; i < 100; ++i)
            {
                Console.Write(".");
                Thread.Sleep(50);
            }
        }
    }
}

另外的一中方法来创建一个线程:new Thread ()

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;

namespace CSharpThread
{
    class Program
    {
        static void ThreadMain ()
        {
            Console.WriteLine("Running in ThreadMain thread");
        }
        static void Main(string[] args)
        {
            Thread t1 = new Thread(ThreadMain);
            t1.Start();
            Console.WriteLine("This is a Main thread");
        }
    }
}

同时还能设置thread的属性:Name等属性

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;

namespace CSharpThread
{
    class Program
    {
        static void ThreadMain ()
        {
            Console.WriteLine("Running in the thread {0}, id : {1}",
                Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId);
        }
        static void Main(string[] args)
        {
            Thread t1 = new Thread(ThreadMain);
            t1.Name = "MyThread";

            t1.Start();
            Console.WriteLine("This is a Main thread");
        }
    }
}

在上面创建的线程是没有传递参数的,那么如何向新开始的线程传递参数?大致上有两种方法:

class Program
{
    public struct Data
    {
        public string Message;
    }

    static void ThreadMain (object o)
    {
        Console.WriteLine( ((Data)o).Message );
    }

    static void Main(string[] args)
    {
        Data d = new Data();
        d.Message = "hello";

        Thread t1 = new Thread(ThreadMain);
        t1.Name = "MyThread";

        /* 传递参数 */
        t1.Start(d);
        Console.WriteLine("This is a Main thread");
    }
}

下面的问题是:

线程的同步和线程之间的参数的传递?

BackgroundWorker使用?

线程的同步和线程之间的参数的传递:http://msdn.microsoft.com/zh-cn/library/ms173179(VS.80).aspx

1.lock来实现:

public void Function()
{
    System.Object lockThis = new System.Object();
    lock(lockThis)
    {
        // Access thread-sensitive resources.
    }
}
2.监视器
lock 关键字类似,监视器防止多个线程同时执行代码块。Enter 方法允许一个且仅一个线程继续执行后面的语句;其他所有线程都将被阻止,直到执行语句的线程调用 Exit。这与使用 lock 关键字一样。事实上,lock 关键字就是用 Monitor 类来实现的。例如:
lock(x)
{
    DoSomething();
}
等价于:
System.Object obj = (System.Object)x;
System.Threading.Monitor.Enter(obj);
try
{
    DoSomething();
}
finally
{
    System.Threading.Monitor.Exit(obj);
}
3.同步事件和等待句柄

用lock和Monitor可以很好地起到线程同步的作用,但它们无法实现线程之间传递事件。如果要实现线程同步的同时,线程之间还要有交互,就要用到同步事件。同步事件是有两个状态(终止和非终止)的对象,它可以用来激活和挂起线程。

  同步事件有两种:AutoResetEvent和 ManualResetEvent。它们之间唯一不同的地方就是在激活线程之后,状态是否自动由终止变为非终止。AutoResetEvent自动变为非终止,就是说一个AutoResetEvent只能激活一个线程。而ManualResetEvent要等到它的Reset方法被调用,状态才变为非终止,在这之前,ManualResetEvent可以激活任意多个线程。

可以通过调用一种等待方法,如 WaitOneWaitAnyWaitAll,让线程等待事件。System.Threading.WaitHandle.WaitOne 使线程一直等待,直到单个事件变为终止状态;System.Threading.WaitHandle.WaitAny 阻止线程,直到一个或多个指示的事件变为终止状态;System.Threading.WaitHandle.WaitAll 阻止线程,直到所有指示的事件都变为终止状态。当调用事件的 Set 方法时,事件将变为终止状态。也就是操作系统课上介绍的p,v操作。

using System;
using System.Threading;

class ThreadingExample
{
    static AutoResetEvent autoEvent;

    static void DoWork()
    {
        Console.WriteLine("   worker thread started, now waiting on event...");
        autoEvent.WaitOne();
        Console.WriteLine("   worker thread reactivated, now exiting...");
    }

    static void Main()
    {
        autoEvent = new AutoResetEvent(false);

        Console.WriteLine("main thread starting worker thread...");
        Thread t = new Thread(DoWork);
        t.Start();

        Console.WriteLine("main thrad sleeping for 1 second...");
        Thread.Sleep(1000);

        Console.WriteLine("main thread signaling worker thread...");
        autoEvent.Set();
    }
}

AutoResetEvent构造函数,用一个指示是否将初始状态设置为终止的布尔值初始化AutoResetEvent 类的新实例。

using System;
using System.Threading;

class CalculateTest
{
    static void Main()
    {
        Calculate calc = new Calculate();
        Console.WriteLine("Result = {0}.", 
            calc.Result(234).ToString());
        Console.WriteLine("Result = {0}.", 
            calc.Result(55).ToString());
    }
}

class Calculate
{
    double baseNumber, firstTerm, secondTerm, thirdTerm;
    AutoResetEvent[] autoEvents;
    ManualResetEvent manualEvent;

    // Generate random numbers to simulate the actual calculations.
    Random randomGenerator;

    public Calculate()
    {
        autoEvents = new AutoResetEvent[]
        {
            new AutoResetEvent(false),
            new AutoResetEvent(false),
            new AutoResetEvent(false)
        };

        manualEvent = new ManualResetEvent(false);
    }

    void CalculateBase(object stateInfo)
    {
        baseNumber = randomGenerator.NextDouble();

        // Signal that baseNumber is ready.
        manualEvent.Set();
    }

    // The following CalculateX methods all perform the same
    // series of steps as commented in CalculateFirstTerm.

    void CalculateFirstTerm(object stateInfo)
    {
        // Perform a precalculation.
        double preCalc = randomGenerator.NextDouble();

        // Wait for baseNumber to be calculated.
        manualEvent.WaitOne();

        // Calculate the first term from preCalc and baseNumber.
        firstTerm = preCalc * baseNumber * 
            randomGenerator.NextDouble();

        // Signal that the calculation is finished.
        autoEvents[0].Set();
    }

    void CalculateSecondTerm(object stateInfo)
    {
        double preCalc = randomGenerator.NextDouble();
        manualEvent.WaitOne();
        secondTerm = preCalc * baseNumber * 
            randomGenerator.NextDouble();
        autoEvents[1].Set();
    }

    void CalculateThirdTerm(object stateInfo)
    {
        double preCalc = randomGenerator.NextDouble();
        manualEvent.WaitOne();
        thirdTerm = preCalc * baseNumber * 
            randomGenerator.NextDouble();
        autoEvents[2].Set();
    }

    public double Result(int seed)
    {
        randomGenerator = new Random(seed);

        // Simultaneously calculate the terms.
        ThreadPool.QueueUserWorkItem(
            new WaitCallback(CalculateBase));
        ThreadPool.QueueUserWorkItem(
            new WaitCallback(CalculateFirstTerm));
        ThreadPool.QueueUserWorkItem(
            new WaitCallback(CalculateSecondTerm));
        ThreadPool.QueueUserWorkItem(
            new WaitCallback(CalculateThirdTerm));

        // Wait for all of the terms to be calculated.
        WaitHandle.WaitAll(autoEvents);

        // Reset the wait handle for the next calculation.
        manualEvent.Reset();

        return firstTerm + secondTerm + thirdTerm;
    }
}
当一个线程开始一个活动(此活动必须完成后,其他线程才能开始)时,它调用 Reset 以将 ManualResetEvent 置于非终止状态。
此线程可被视为控制ManualResetEvent。调用 ManualResetEvent 上的 WaitOne 的线程将阻止,并等待信号。当控制线程完成活
动时,它调用 Set 以发出等待线程可以继续进行的信号。并释放所有等待线程。更通俗的解释:http://hi.baidu.com/kissxrl/blog/item/fe59499055d6518ba877a450.html
其区别就在调用后,AutoResetEvent.WaitOne()每次只允许一个线程进入,当某个线程得到信号后,AutoResetEvent会自动又将信号置
为不发送状态,则其他调用WaitOne的线程只有继续等待.也就是说,AutoResetEvent一次只唤醒一个线程;而ManualResetEvent则可以
唤醒多个线程,因为当某个线程调用了ManualResetEvent.Set()方法后,其他调用WaitOne的线程获得信号得以继续执行,而ManualResetEvent
不会自动将信号置为不发送。也就是说,除非手工调用了ManualResetEvent.Reset()方法,则ManualResetEvent将一直保持有信号状态,
ManualResetEvent也就可以同时唤醒多个线程继续执行。
上面的程序中涉及到了线程池的概念,使用方法如下:http://msdn.microsoft.com/zh-cn/library/3dasc8as(VS.80).aspx

“线程池”是可以用来在后台执行多个任务的线程集合。(有关背景信息,请参见使用线程处理。)这使主线程可以自由地异步执行其他任务。

线程池通常用于服务器应用程序。每个传入请求都将分配给线程池中的一个线程,因此可以异步处理请求,而不会占用主线程,也不会延迟后续请求的处理。

一旦池中的某个线程完成任务,它将返回到等待线程队列中,等待被再次使用。这种重用使应用程序可以避免为每个任务创建新线程的开销。

线程池通常具有最大线程数限制。如果所有线程都繁忙,则额外的任务将放入队列中,直到有线程可用时才能够得到处理。

您可以实现自己的线程池,但是通过 ThreadPool 类使用 .NET Framework 提供的线程池更容易一些。

下面的示例使用 .NET Framework 线程池计算 20 和 40 之间的十个数的 Fibonacci 结果。每个 Fibonacci 结果都由 Fibonacci 类表示,该类提供一种名为ThreadPoolCallback 的方法来执行此计算。将创建表示每个 Fibonacci 值的对象,ThreadPoolCallback 方法将传递给 QueueUserWorkItem,它分配池中的一个可用线程来执行此方法。

由于为每个 Fibonacci 对象都提供了一个半随机值来进行计算,而且十个线程都将竞争处理器时间,因此无法提前知道十个结果全部计算出来所需的时间。因此在构造期间为每个 Fibonacci 对象传递 ManualResetEvent 类的一个实例。当计算完成时,每个对象都通知提供的事件对象,使主线程用 WaitAll 阻止执行,直到十个 Fibonacci对象全部计算出了结果。然后 Main 方法将显示每个 Fibonacci 结果。

示例

C#

using System;
using System.Threading;

public class Fibonacci
{
    public Fibonacci(int n, ManualResetEvent doneEvent)
    {
        _n = n;
        _doneEvent = doneEvent;
    }

    // Wrapper method for use with thread pool.
    public void ThreadPoolCallback(Object threadContext)
    {
        int threadIndex = (int)threadContext;
        Console.WriteLine("thread {0} started...", threadIndex);
        _fibOfN = Calculate(_n);
        Console.WriteLine("thread {0} result calculated...", threadIndex);
        _doneEvent.Set();
    }

    // Recursive method that calculates the Nth Fibonacci number.
    public int Calculate(int n)
    {
        if (n <= 1)
        {
            return n;
        }

        return Calculate(n - 1) + Calculate(n - 2);
    }

    public int N { get { return _n; } }
    private int _n;

    public int FibOfN { get { return _fibOfN; } }
    private int _fibOfN;

    private ManualResetEvent _doneEvent;
}

public class ThreadPoolExample
{
    static void Main()
    {
        const int FibonacciCalculations = 10;

        // One event is used for each Fibonacci object
        ManualResetEvent[] doneEvents = new ManualResetEvent[FibonacciCalculations];
        Fibonacci[] fibArray = new Fibonacci[FibonacciCalculations];
        Random r = new Random();

        // Configure and launch threads using ThreadPool:
        Console.WriteLine("launching {0} tasks...", FibonacciCalculations);
        for (int i = 0; i < FibonacciCalculations; i++)
        {
            doneEvents[i] = new ManualResetEvent(false);
            Fibonacci f = new Fibonacci(r.Next(20,40), doneEvents[i]);
            fibArray[i] = f;
            ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i);
        }

        // Wait for all threads in pool to calculation...
        WaitHandle.WaitAll(doneEvents);
        Console.WriteLine("All calculations are complete.");

        // Display the results...
        for (int i= 0; i<FibonacciCalculations; i++)
        {
            Fibonacci f = fibArray[i];
            Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN);
        }
    }
}
2.BackgroundWorker使用?
http://msdn.microsoft.com/zh-cn/library/system.componentmodel.backgroundworker(VS.95).aspx
BackgroundWorker 类允许您在单独的专用线程上运行操作。诸如下载和数据库事务这样的耗时操作会导致用户界面停止响应。如果您需
要能进行响应的用户界面,而且必须执行耗时操作,则可以使用 BackgroundWorker 类方便地解决问题。在https://cid-f41b44b9285d0b86.skydrive.live.com/browse.aspx/.Documents/学习资料/c^3相关?uc=1
中有一个demo,解决的就是ProgressBar的问题

posted @ 2010-03-29 19:17  qiang.xu  阅读(13525)  评论(0编辑  收藏  举报