【.NET】【线程】

//线程同步lock Monitor
lock(this) 锁定 当前实例对象,如果有多个类实例的话,lock锁定的只是当前类实例,对其它类实例无影响。所有不推荐使用。 
lock(typeof(Model))锁定的是model类的所有实例。 这里的Model是指某个类名。
lock(obj)锁定的对象是全局的私有化静态变量。外部无法对该变量进行访问。 
lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。 
所以,lock的结果好不好,还是关键看锁的谁,如果外边能对这个谁进行修改,lock就失去了作用。
所以,一般情况下,使用私有的、静态的并且是只读的对象


lock(obj) {     //代码段        } 
//就等同于 
Monitor.Enter(obj); 
//代码段
Monitor.Exit(obj);  


.net4.0或以上推荐用!!!!!!!!.NET 4.5引入了async和await关键字
Task对线程,线程池的封装 (没执行完程序就关闭了,是后台线程)
Task task = new Task(()=>{
void 要调用方法()
}); 
task.Start();  //开始线程为Start(),等待线程结束为Wait()。
线程执行完毕后调用另一个线程,也就是两个线程,有序的执行,使用ContinueWith(),
总结1:Task的使用比Thread简单很多,减少了同步,等待等等问题,唯一的遗憾是不支持Thread的IsBackground。
结论1:如果不需要使用IsBackground,那么尽情的使用Task吧。经测试,Task是后台线程,也就是Isbackground=true;

防止一个线程重复调用
if (mThread!= null)
{
    if (mThread.IsAlive || mThread.ThreadState == System.Threading.ThreadState.Running)
    {
        mThread.Abort();
    }
    mThread = null;
}
mThread= new Thread(new ThreadStart(delegate()
{
}));

传统线程
Thread t = new Thread(new ParameterizedThreadStart(gp点叠加易发));//带参数
t.SetApartmentState(ApartmentState.STA);
int[] args={four,three,two,one};
t.Start(args);
t.Join(); // 等待t线程完成后,主线程才继续执行!

Thread t = new Thread(new ThreadStart(DataMapping.gp雨量计算));//不带参数
t.SetApartmentState(ApartmentState.STA);
t.Start();

后台线程:后台线程是可以随时被CLR关闭而不引发异常的
前台线程:执行确实想完成的任务,比如数据的拷贝等等



--------------------------------------------------------------------------------
线程池
    //在什么情况下使用线程池来创建线程? 
    1.单个任务处理的时间比较短 
    2.需要处理的任务的数量大


子线程调用ui
调用控件的Invoke方法,Invoke方法会顺着控件树向上搜索,直到找到创建控件的那个线程(通常是主线程),然后进入那个线程改变控件的外观,确保不发生线程冲突。
this.Invoke(new EventHandler(delegate
{
    button.Text="关闭";
}));
wpf的子线程调用ui
为了让后台线程访问Button的Content属性,后台线程必须将工作委托给与 UI线程关联的Dispatcher,这是通过使用Invoke(同步,立即执行)或BeginInvoke(异步,不立即执行)来完成的,通过调用BeginInvoke将异步作业排队到UI线程的Dispatcher(提供用于管理线程的工作项队列的服务)上。当UI线程处于SystemIdle(CPU空闲)状态时,在队列上推送的作业处理一个数字,并在下一次UI线程空闲时在调度程序上推送另一个调用以处理下一个数字。这可以确保UI线程始终优先于计算下一个数字,并使UI不会挂起。
this.Dispatcher.Invoke(new Action(()=>{
                        progress .Value = 100;
                        status .Content = "更新完成";
                }),null);


传统方法更新进度到ui(子线程):		
private delegate void 子线程的代理(string MSG);//来一个代理,代理把子线程的方法传给主窗体线程
Thread pThread1 = new Thread(new ThreadStart(某方法));//某方法里面要更新ui,所以new一个线程让它运行,它要更新ui就调用,更新ui的方法(msg)
pThread1.IsBackground=true;
pThread1.Start();
		private void 更新ui的方法(string msg)
		{
			if (this.InvokeRequired == false)//判断是否需要调用主窗体线程,若不需要
			{
				textBox1.AppendText(msg + "\r\n");
				textBox1.ScrollToCaret();
			}
			else //若需要调用主窗体线程,就代理给主窗体线程呗!!!!                                                
			{
				子线程的代理 代理 = new 子线程的代理(p增加到消息日志);
				this.Invoke(代理, msg);//用主窗体来更新ui
			}
		}





线程池最多管理线程数量=“处理器数 * 250”。也就是说,如果您的机器为2个2核CPU,那么CLR线程池的容量默认上限便是1000
通过线程池创建的线程默认为后台线程,优先级默认为Normal。


ThreadPool.SetMinThreads(MaxThreadCount, 10);
//第一参数是设置线程池辅助线程,第二个值是设置异步I/O线程
//CLR线程池分为工作者线程(workerThreads)与I/O线程(completionPortThreads)两种。当你的程序是I/O密集型时,你应该将线程数向I/O偏移,如果你的程序是CPU密集型时,你应该将线程数向工作线程偏移。
// 设置最大空闲线程为500,就好像我告诉系统给我预先准备500个线程我来了就直接用,因为这样就不用现去申请了              //在线程池中每申请一个新的线程.NET Framework 会安排一个间隔时间,目前是半秒,以后的版本MS有可能会改

ThreadPool.QueueUserWorkItem(new WaitCallback(方法), 参数object);    //参数可选

//判断线程池里的线程是否都执行完毕了
while (true)
            {
                Thread.Sleep(1000);//这句写着,主要是没必要循环那么多次。去掉也可以。
                int maxWorkerThreads, workerThreads;
                int portThreads;
                ThreadPool.GetMaxThreads(out maxWorkerThreads, out portThreads);
                ThreadPool.GetAvailableThreads(out workerThreads, out portThreads);
                Console.WriteLine("maxWorkerThreads:"+maxWorkerThreads+ "  workerThreads:"+workerThreads);
                if (maxWorkerThreads - workerThreads == 0)
                {
                    Console.WriteLine("结束了");
                    break;
                }
            }



//4 后台BackgroundWorker
         开始
        BGWorker.DoWork += 要后台的方法;
        BGWorker.RunWorkerAsync(方法的参数);
        void 要后台的方法(object sender, DoWorkEventArgs e);//e.Argument来获取方法的参数
        
        把进度传递给UI:
        BGWorker.WorkerReportsProgress = true;
        BGWorker.ProgressChanged += 进度改变要干什么的函数;
        bgWorker.ReportProgress(progressNum, "message");//更新进度
        void 进度改变要干什么的函数(object sender, ProgressChangedEventArgs e);{this.progressBar.Value = e.ProgressPercentage;}
        //如果有更多的信息需要传递,可以使用 e.UserState 传递一个自定义的类型。/这是一个 object 类型的对象,您可以通过它传递任何类型。
        
        取消
        允许取消:BGWorker.WorkerSupportsCancellation = true;
        点击取消:BGWorker.CancelAsync();
        点击取消后:在要后台的方法中判断点击了取消 if(BGWorker.CancellationPending){e.Cancel = true;return; }
        
        后台操作完成后,反馈结果给用户
        BGWorker.RunWorkerCompleted += 运行完成要执行的函数;
        private void 运行完成要执行的函数(object sender, RunWorkerCompletedEventArgs e)
        {
        //DoWork 设置e.Result,RunWorkerCompleted里接收e.Result
        //e.Error错误
        if(e.Cancelled)
               MessageBox.Show("被取消");
        else
               MessageBox.Show("完成");
        }


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值