学习进程和线程时的一点基础笔记(一)---------基础片 (ZHUANZAI)
在c#中有专门处理进程和线程的类: Process类和Thread类
进程相关代码:
process1.StarInfo.FileName="notepad.exe" //指定启动进程时使用的一组值
process1.Start(); //启动Notepad.exe进程
//创建新的Process组件的数组,并将它们与指定的进程名称(Notepad)的所有进程资源相关联。
Process [] myprocesses;
myprocesses=Process.GetProcessesByName(“Notepad”) ;
foreach(Process instance in myprocesses)
{
//设置终止当前线程前等待1000毫秒
instance.WaitForExit(1000);
instance.CloseMainWindows();
}
//////////////////////////////////////// listBox 显示所有进程//////////////////////////////////
listBox1.Items.Clear();
//创建Process类型的数组,并将它们与系统内所有进程关联
Process[] processes;
processes=Process.GetProcesses();
foreach(Process p in processes)
{
//Idle 指显示CPU空闲率的进程名称
//由于访问Idle的StarTime会出现异常,所以将其排除在外
if(p.ProcessName !="Idle")
{
//将每个进程名和进程开始时间加入Listbox1中
this。listBox1.Items.Add(string.Format("{0,-30}{l;h;s}",p.ProcessName,p.StartTime));
}
}
////////////////////////////////////////////////////////////////////////// Thread 类------线程 ////////////////////////////////////////////////////////////////
Thread类 位于System.Threading 命名空间下 包含了创建和控制线程的Thread类。对线程的常用操作有:启动线程,终止线程,合并线程和让线程休眠等。
1.启动线程
在使用线程前,首先创建一个线程 Thread t=new Thread(enterPoint); //enterPoint 为线程的入口
Thread t=new Thread(new ThreadStart(methodName)); //在托管代码中,通过委托处理线程执行的代码
创建线程后,调用Start方法启动线程
2.终止线程
两种终止线程的方法:
《1》事先设置一个BOOL型变量,在其他线程中通过修改变量的值作为传递给该线程是否需要终止的判断条件,而在该线程中的循环判断条件,以确定是否退出线程,这是结束线程的比较好的方法,实际编程中的一般使用这种方法。
《2》通过调用Thread 类的Abort方法强行终止进程。例如: t.Abort();
Abort方法没有任何参数,线程一旦被终止,就无法重新启动。 Abort 通过抛出异常{ThreadAbortException}强行终止结束进程。
可以捕获ThreadAbortException异常,然后在异常处理的Catch块或者Finally块中做释放资源等代码的处理工作
线程捕获 异常,系统在finally子句的结尾会再次引发异常,可以在finally子句结尾处或者Catch子句结尾处调用Sysetem.Threading.Thread.ResetAbort方法防止系统再次引发异常;Abort 终止线程需要一点时间,因为结束前要进行代码清理工作,清理工作没有结束,可能出现类似死机的假象,未解决问题,可以在主线程中调用子线程对象的join方法,并在join方法中指定主线程等待子线程结束的等待时间
例如: thread1.Abort();
thread1.Join(10);
3合并线程
join 方法把两个并行执行的线程合并为一个单个的线程。如果一个线程T1在执行的过程中需要等待另一个线程T2结束后才能继续执行,可以在T1的程序模块中调用T2的join()方法 例如 T2.join 在T1执行到T2.join()语句后会处于阻塞状态,知道T2结束继续执行 T2.join(100)// T1只等待100毫秒
4线程休眠
让进程暂停一段时间继续进行
Thread.Sleep(1000);
5线程优先级
当线程争夺CPU时间片时,CPU是按照线程的优先级进行服务的。五个优先级由高到低:Highest,AboveNormal,Normal,BelowNormal和Lowest
在创建进程时如果不指定其优先级,则系统默认为Normal
例如:Thread t=new Thread(new ThreadStart(enterpoint));
t.priority=ThreadPriority.AboveNormal;
注意:当把某线程优先级设置为Highest时,系统正在运行的其他线程都会终止,所以使用这个优先级别时要特别小心。
6.线程池
作用:限制同一时间处理的线程数
线程池适用于:需要多个线程而实际执行时间又不多的场合
方式:线程重用,调整线程池中的线程数目
7.同步
所谓同步是指多个线程之间存在先后执行顺序的关联关系。
例如:如线程T1对variable1操作时,避免其他线程对其操作,可以使用lock语句锁定variable1,实现代码
lock(variable1)
{
variable1++;
}
注意锁定的对象一定要声明为private,不要锁定public类型的对象,否则失控
join 方法把两个并行执行的线程合并为一个单个的线程。如果一个线程T1在执行的过程中需要等待另一个线程T2结束后才能继续执行,可以在T1的程序模块中调用T2的join()方法 例如 T2.join 在T1执行到T2.join()语句后会处于阻塞状态,知道T2结束继续执行 T2.join(100)// T1只等待100毫秒
-----------------------------UPDATE UI------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using DelegateDemo;
namespace ThreadDemo
{
public partial class Form1 : Form
{
private delegate void MyDelegate(string s);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//ThreadStart ts = new ThreadStart(SampleThread1);
//Thread t = new Thread(ts);
//t.Start();
//Thread t2 = new Thread(new ThreadStart(SampleThread2));
//t2.Start();
//ParameterizedThreadStart t3 = new ParameterizedThreadStart(DoWork);
//Thread th3 = new Thread(t3);
//th3.Start();
ThreadStart mEagleThreadDelegate = new ThreadStart(this.method1);
Thread mEagleThread = new Thread(mEagleThreadDelegate);
mEagleThread.Start();
}
public void method1()
{
for (int i = 0; i < 10000; i++)
{
Thread.Sleep(100);
string result = "odc id";
if (i < 100)
{
result = "hkjc id";
}
//this.Invoke(new Action<string>(this.UpdateProgress), i);
this.BeginInvoke(new Action<string>(this.UpdateUI), result);
//通过 Invoke 或者 BeginInvoke 去调用,两者的区别就是一个导致工作线程等待,而另外一个则不会
}
}
private void UpdateUI(string v)
{
this.listBox1.Items.Add(v.ToString());
textBox1.Text = v.ToString();
}
/// <summary>
/// 定义线程入口方法,并传递参数,注意这里的参数必须是object类型,在内部根据需要自行作类型转换
/// </summary>
/// <param name="obj"></param>
private void DoWork(object obj)
{
object obj1 = new object();
lock (obj1)
{
string s = (string)obj;//根据需要对参数进行类型转换
MyDelegate md = new MyDelegate(SetText);//创建委托实例
Thread.Sleep(1 * new Random().Next(1, 32000));//随机休眠1-3000毫秒,有利于看清UI的更新,如果设置为固定时间,你几乎感觉不到是实时更新
/*
Do Some Work
*/
this.BeginInvoke(md,s);//UI线程上异步调用委托
}
}
/// <summary>
/// UI线程中用于更新界面的方法,其签名与上面定义的委托MyDelegate相同
/// </summary>
/// <param name="s"></param>
private void SetText(string s)
{
string s1 = s + "." + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:mm.ffffff");
listBox1.Items.Add(s1);
this.textBox1.Text = s1;//如果10个线程你看不到逐个添加的效果,可能就是因为你的CPU处理速度比较快,请加大线程数量,这样可以看到滚动条在不断变窄,或者你也可以在此加上Label单条显示,这样更明显
}
public void SampleThread1()
{
for (int i = 1; i < 1000; i++)
{
}
}
public void SampleThread2()
{
}
public void SampleThread3(Object str)
{
for (int i = 1; i < 1000; i++)
{
}
}
}
}
--------other method----------------------------------------------
void DisplayMessage(object sender, MessageArgs e)
{
if (this.InvokeRequired)
{
MessageHandler handler = DisplayMessage;
this.Invoke(handler, sender, e);
}
else
{
if (e.MessageType == MessageType.Information)
{
lbxInformation.Items.Add(e.Message);
}
else if (e.MessageType == MessageType.Error)
{
lbxError.Items.Add(e.Message);
}
}
}
----------remark---------------------------------------------------
1.Invoke 和 BeginInvoke
在多线程编程中,我们经常要在工作线程中去更新界面显示,而在多线程中直接调用界面控件的方法是错误的做法,正确的做法是将工作线程中涉及更新界面的代码封装为一个方法,通过 Invoke 或者 BeginInvoke 去调用,两者的区别就是一个导致工作线程等待,而另外一个则不会。
而所谓的“一面响应操作,一面添加节点”永远只能是相对的,使 UI 线程的负担不至于太大而以,因为界面的正确更新始终要通过 UI 线程去做,我们要做的事情是在工作线程中包揽大部分的运算,而将对纯粹的界面更新放到 UI 线程中去做,这样也就达到了减轻 UI 线程负担的目的了。
2.Application.DoEvent
在耗时的循环的UI更新的方法中,插入Application.DoEvent,会使界面获得响应,Application.DoEvent会调用消息处理程序。
3.Lock
lock(object)
{
}
等价与
try
{
Monitor.Enter(object);
}
finally
{
Monitor.Exit(object)
}