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)
- //更新进度列表
- private delegate void SetPos(int ipos);
第三步:进度条值更新函数(参数必须跟声明的代理参数一样)
- private void SetTextMessage(int ipos)
- {
- if (this.InvokeRequired)
- {
- SetPos setpos = new SetPos(SetTextMessage);
- this.Invoke(setpos, new object[] { ipos});
- }
- else
- {
- this.label1.Text = ipos.ToString() + "/100";
- this.progressBar1.Value = Convert.ToInt32(ipos);
- }
- }
第四步:函数实现
- private void button1_Click(object sender, EventArgs e)
- {
- Thread fThread = new Thread(new ThreadStart(SleepT));//开辟一个新的线程
- fThread.Start();
- }
第五步:新的线程执行函数:
- private void SleepT()
- {
- for (int i = 0; i < 500; i++)
- {
- System.Threading.Thread.Sleep(100);//没什么意思,单纯的执行延时
- SetTextMessage(100 * i / 500);
- }
- }
上面涉及到了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可以激活任意多个线程。
可以通过调用一种等待方法,如 WaitOne、WaitAny 或 WaitAll,让线程等待事件。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的问题
作者:许强1. 本博客中的文章均是个人在学习和项目开发中总结。其中难免存在不足之处 ,欢迎留言指正。 2. 本文版权归作者和博客园共有,转载时,请保留本文链接。