首页 > 技术文章 > 委托&&异步

jimmy-zhang 2017-04-11 10:10 原文

 后台线程不会阻止进程的关闭。当某个程序的所有前台线程完成后,进程就终止程序退出了,当然后台线程也会随即停止。在.NET中用Thread创建的线程默认都是前台线程,用线程池、BeginXXX等启用的线程都是后台线程

线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,实现线程同步的方法有很多,临界区对象就是其中一种。

同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。

“同”字从字面上容易理解为一起动作
其实不是,“同”字应是指协同、协助、互相配合。
如进程、线程同步,可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B依言执行,再将结果给A;A再继续操作。
在多线程编程里面,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何时刻,最多有一个线程访问,以保证数据的完整性。

 

  • 新建一个线程(无参数,无返回值)

Thread th = new Thread(new ThreadStart(PrintName)); 

 public  void PrintName()    // 函数 

 { 

     //函数体 

 } 

  •  有参数时

Thread th = new Thread(new ParameterizedThreadStart(PrintName)); 

public  void PrintName(string name)    // 函数

{

 //函数体 

}

 

  •  如果遇到又需要返回值,又需要参数的时候,就可以考虑用异步

但是需要先申明个委托

public delegate string MethodCaller(string name);//定义个代理 

MethodCaller mc = new MethodCaller(GetName); 

string name = "my name";//输入参数 

IAsyncResult result = mc.BeginInvoke(name,null, null); 

string myname = mc.EndInvoke(result);//用于接收返回值 

 

public string GetName(string name)    // 函数

{

return name;

}


 避免使用 BeginInvoke(在控件中使用)

 

 


 

        private void ShowMessage(string message)
        {
            this.BeginInvoke(new MethodInvoker(delegate
            {
                txtSysMessage.Text += message +"-------"+DateTime.Now.ToString()+ "\r\n";
            }));
        }
View Code

 

        private void ShowMessage3(string message)
        {
            txtSysMessage.BeginInvoke((MethodInvoker)delegate
            {
                txtSysMessage.Text += message + "-------" + DateTime.Now.ToString() + "\r\n";
            });
        }
View Code

 

        private void ShowMessage1(string message)
        {
            listBoxMessage.BeginInvoke((MethodInvoker)delegate
            {
                if (listBoxMessage.Items.Count > 200)
                {
                    listBoxMessage.Items.RemoveAt(0);
                }
                listBoxMessage.Items.Add(message + "-------" + DateTime.Now.ToString());
            });
        }
View Code

 

 

 


 

public static void Dispatch(Action action)
        {
            if (DispatchObject == null || DispatchObject.CheckAccess())
            {
                action();
            }
            else
            {
                DispatchObject.Invoke(action);
            }
        }
this.validationErrorService.ErrorsChangedEvent += delegate(object sender, EventArgs args)
            {
                DispatcherService.Dispatch(() =>
                {
                    this.validationErrorsView.ErrorsDataGrid.ItemsSource = this.validationErrors;
                    this.validationErrorsView.ErrorsDataGrid.Items.Refresh();
                });
            };

 

 

 这种技术常用在2个或者多个线程需要独占访问某系资源的情况下

AutoResetEvent 允许线程通过发信号互相通信。通常,此通信涉及线程需要独占访问的资源。

线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号。如果 AutoResetEvent 处于非终止状态,则该线程阻塞,并等待当前控制资源的线程
通过调用 Set 发出资源可用的信号。

 

可以通过将一个布尔值传递给构造函数来控制  AutoResetEvent 的初始状态,如果初始状态为

   终止状态 true

非终止状态 false 如果 AutoResetEvent 处于非终止状态,则该线程阻塞,并等待当前控制资源的线程,通过调用 Set 发出资源可用的信号。

 通俗的来讲只有等myResetEven.Set()成功运行后,myResetEven.WaitOne()才能够获得运行机会;Set是发信号,WaitOne是等待信号,只有发了信号,
等待的才会执行。如果不发的话,WaitOne后面的程序就永远不会执行。

初始化需要注意的是,一般初始化为“未信号”,也就是所谓的“Not signaled”。关于这一点,文档的解释是“可以通过将一个布尔值传递给构造函数来控制 AutoResetEvent 的初始状态,如果初始状态为终止状态,则为 true;否则为 false。”也就是说Not Signaled=非终止状态。一般情况下我看大多数程序都是初始化为“非终止状态”的。这里面的原因很显然:非终止状态可以等待一个信号来释放线程


 

相关参考:http://blog.csdn.net/jcx5083761/article/details/8552627

1,Delegate的代码

 1         public delegate void myDelegate(string str);
 2         public static void HellowChinese0(string strChinese)
 3         {
 4             Console.WriteLine("Good morning," + strChinese);
 5         }
 6 
 7         private static void demo0()
 8         {
 9             myDelegate d = new myDelegate(HellowChinese0);
10             d("demo0");
11         }

 

2,Action:指定那些只有输入参数,没有返回值的委托

 1         public static void HellowChinese(string strChinese)
 2         {
 3             Console.WriteLine("Good morning," + strChinese);
 4         }
 5 
 6         static void demo1()
 7         {
 8             Action<string> action = HellowChinese;
 9             action("demo1");
10         }

 

3,Func:有返回值!

1         public static string HelloEnglish(string strEnglish)
2         {
3             return "Good morning," + strEnglish;
4         }
5         static void demo2()
6         {
7             Func<string, string> f = HelloEnglish;
8             Console.WriteLine(f("demo2"));
9         }

 


 

Invoke,需要等待委托的方法执行返回后才执行下面的代码
begininvoke不需要
Invoke:同步,使用主线程
BeginInvoke:异步,另外起一个线程



sleep和wait都是使线程暂时停止执行的方法,但它们有很大的不同。


1. sleep是线程类Thread 的方法,它是使当前线程暂时睡眠,可以放在任何位置。而wait,它是使当前线程暂时放弃对象的使用权进行等待,必须放在同步方法或同步块里。

2.Sleep使用的时候,线程并不会放弃对象的使用权,即不会释放对象锁,所以在同步方法或同步块中使用sleep,一个线程访问时,其他的线程也是无法访问的。

而wait是会释放对象锁的,就是当前线程放弃对象的使用权,让其他的线程可以访问。

3.线程执行wait方法时,需要其他线程调用Monitor.Pulse()或者Monitor.PulseAll()进行唤醒或者说是通知等待的队列。

而sleep只是暂时休眠一定时间,时间到了之后,自动恢复运行,不需另外的线程唤醒.

 

推荐阅读