同步

同步(英语:Synchronization [ˌsɪŋkrənaɪ'zeɪʃn]),指对在一个系统中所发生的事件(event)之间进行协调,在时间上出现一致性与统一化的现象。说白了就是多个任务一个一个执行,同一时刻只有一个任务在执行。主要应用是互斥资源的访问。下面是实现同步的一个例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApplicationSyncTest
{
class InterProcessSync
{
static void Main(string[] args)
{
string MutexName = "InterProcessSyncName";
Mutex SyncNamed; //声明一个已命名的互斥对象
try
{
SyncNamed = Mutex.OpenExisting(MutexName); //如果此命名互斥对象已存在则请求打开
}
catch (WaitHandleCannotBeOpenedException)
{
SyncNamed = new Mutex(false, MutexName); //如果初次运行没有已命名的互斥对象则创建一个
}
Task MulTask = new Task(() => //多任务并行计算中的匿名方法,用委托也可以
{
while(ture) //为了效果明显而设计
{
Console.WriteLine("当前进程等待获取互斥访问权......");
SyncNamed.WaitOne();
Console.WriteLine("获取互斥访问权,访问资源完毕,按回车释放互斥资料访问权.");
Console.ReadLine();
SyncNamed.ReleaseMutex();
Console.WriteLine("已释放互斥访问权。");
}
} ); MulTask.Start();
MulTask.Wait();
} }
}

以上程序编译后,请运行两个实例即两个进程。就可以明显的看出进程间的同步的实现。

线程

线程是进程中某个单一顺序的控制流。也被称为轻量进程(lightweight processes).计算机科学术语,指运行中的程序的调度单位.
当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。以CAsyncSocket类为例(注意,CSocket从CAsyncSocket派生,但是其功能已经由异步转化为同步),当一个客户端通过调用Connect函数发出一个连接请求后,调用者线程立刻可以朝下运行。当连接真正建立起来以后,socket底层会发送一个消息通知该对象。这里提到执行部件和调用者通过三种途径返回结果:状态、通知和回调。可以使用哪一种依赖于执行部件的实现,除非执行部件提供多种选择,否则不受调用者控制。如果执行部件用状态来通知,那么调用者就需要每隔一定时间检查一次,效率就很低(有些初学多线程编程的人,总喜欢用一个循环去检查某个变量的值,这其实是一种很严重的错误)。如果是使用通知的方式,效率则很高,因为执行部件几乎不需要做额外的操作。至于回调函数,其实和通知没太多区别。

并行

一般指并行计算,是说同一时刻有多条指令同时被执行,这些指令可能执行于同一CPU的多核上,或者多个CPU上,或者多个物理主机甚至多个网络中.

异步

与同步相对应,异步指的是让CPU暂时搁置当前请求的响应,处理下一个请求,当通过轮询或其他方式得到回调通知后,开始运行。多线程将异步操作放入另一线程中运行,通过轮询或回调方法得到完成通知,但是完成端口,由操作系统接管异步操作的调度,通过硬件中断,在完成时触发回调方法,此方式不需要占用额外线程

异步C#异步与多线程的异同点

异步和多线程两者都可以达到避免调用线程阻塞的目的,从而提高软件的可响应性。
异步操作无须额外的线程负担,并且使用回调的方式进行处理,在设计良好的情况下,处理函数可以不必使用共享变量(即使无法完全不用,最起码可以减少 共享变量的数量),减少了死锁的可能。当然异步操作也并非完美无暇。编写异步操作的复杂程度较高,程序主要使用回调方式进行处理,与普通人的思维方式有些 出入,而且难以调试。当需要执行I/O操作时,使用异步操作比使用线程+同步 I/O操作更合适。
多线程中的处理程序依然是顺序执行,符合普通人的思维习惯,所以编程简单。但是多线程的缺点也同样明显,线程的使用(滥用)会给系统带来上下文切换的额外负担。并且线程间的共享变量可能造成死锁的出现。多线程的适用范围则是那种需要长时间CPU运算的场合,例如耗时较长的图形处理和算法执行。
control的同步和异步
(1)Control的Invoke和BeginInvoke与Delegate的Invoke和BeginInvoke是不同的。
(2)Control的Invoke和BeginInvoke的参数为delegate,委托的方法是在Control的线程上执行的,也就是我们平时所说的UI线程。
control的invoke:
private delegate void InvokeDelegate();
private void InvokeMethod(){
//C代码段
}
private void butInvoke_Click(object sender, EventArgs e) {
//A代码段.......
this.Invoke(new InvokeDelegate(InvokeMethod));
//B代码段......
}

执行顺序为:
A------>C---------------->B
解释:

(1)A在UI线程上执行完后,开始Invoke,Invoke是同步
(2)代码段B并不执行,而是立即在UI线程上执行InvokeMethod方法,即代码段C。
(3)InvokeMethod方法执行完后,代码段B才在UI线程上继续执行。

control的begininvoke

private delegate void BeginInvokeDelegate();
private void BeginInvokeMethod(){
//C代码段
}
private void butBeginInvoke_Click(object sender, EventArgs e) {
//A代码段.......
this.BeginInvoke(new BeginInvokeDelegate(BeginInvokeMethod));
//B代码段....}

执行顺序:
A----------->B--------------->C
解释:

(1)A在UI线程上执行完后,开始BeginInvoke,BeginInvoke是异步
(2)InvokeMethod方法,即代码段C不会执行,而是立即在UI线程上执行代码段B。
(3)代码段B执行完后(就是说butBeginInvoke_Click方法执行完后),InvokeMethod方法,即代码段C才在UI线程上继续执行。

 
Control的Invoke和BeginInvoke的委托方法是在主线程,即UI线程上执行的。也就是说如果你的委托方法用来取花费时间长的数据,然后更新界面,千万不能调用UI线程上调用Control.Invoke和Control.BeginInvoke,因为这些是依然阻塞UI线程的,造成界面的假死。

那么,这个异步到底是什么意思呢?
异步是指相对于调用BeginInvoke的线程异步,而不是相对于UI线程异步,你在UI线程上调用BeginInvoke ,当然不行了。(无论如何都在ui进程上执行)
BeginInvoke的原理是将调用的方法Marshal成消息,然后调用Win32 API中的RegisterWindowMessage()向UI窗口发送消息。

我们用Thread来调用BeginInvoke和Invoke
private Thread invokeThread;
private delegate void invokeDelegate();
private void StartMethod(){
//C代码段......
Control.Invoke(new invokeDelegate(invokeMethod));
//D代码段......
}
private void invokeMethod(){
//E代码段
}
private void butInvoke_Click(object sender, EventArgs e) {
//A代码段.......
invokeThread = new Thread(new ThreadStart(StartMethod));
invokeThread.Start();
//B代码段......
}

A------>(Start一开始B和StartMethod的C就同时执行)---->(C执行完了,不管B有没有执行完,invokeThread把消息封送(invoke)给UI线程,然后自己等待)---->UI线程处理完butInvoke_Click消息后,处理invokeThread封送过来的消息,执行invokeMethod方法,即代码段E,处理往后UI线程切换到invokeThread线程。

解释:
1。UI执行A
2。UI开线程InvokeThread,B和C同时执行,B执行在线程UI上,C执行在线程invokeThread上。
3。invokeThread封送消息给UI,然后自己等待,UI处理完消息后,处理invokeThread封送的消息,即代码段E
4。UI执行完E后,转到线程invokeThread上,invokeThread线程执行代码段D

private Thread beginInvokeThread;
private delegate void beginInvokeDelegate();
private void StartMethod(){
//C代码段......
Control.BeginInvoke(new beginInvokeDelegate(beginInvokeMethod));
//D代码段......
}
private void beginInvokeMethod(){
//E代码段
}
private void butBeginInvoke_Click(object sender, EventArgs e) {
//A代码段.......
beginInvokeThread = new Thread(new ThreadStart(StartMethod));
beginInvokeThread .Start();
//B代码段......
}

A在UI线程上执行----->beginInvokeThread线程开始执行,UI继续执行代码段B,并发地invokeThread执行代码段C-------------->不管UI有没有执行完代码段B,这时beginInvokeThread线程把消息封送给UI,单自己并不等待,继续向下执行-------->UI处理完butBeginInvoke_Click消息后,处理beginInvokeThread线程封送过来的消息。

解释:
1。UI执行A
2。UI开线程beginInvokeThread,B和C同时执行,B执行在线程UI上,C执行在线程beginInvokeThread上。
3。beginInvokeThread封送消息给UI,然后自己继续执行代码D,UI处理完消息后,处理invokeThread封送的消息,即代码段E
有点疑问:如果UI先执行完毕,是不是有可能过了段时间beginInvokeThread才把消息封送给UI,然后UI才继续执行封送的消息E。如图浅绿的部分。

Control的BeginInvoke是相对于调用它的线程,即beginInvokeThread相对是异步的。
因此,我们可以想到。如果要异步取耗费长时间的数据,比如从数据库中读大量数据,我们应该这么做。
(1)如果你想阻止调用线程,那么调用代码(三),代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。
(2)如果你不想阻止调用线程,那么调用代码(四),代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。
 
委托还能写成下面的两种形式
        public delegate void NoparamDelegate(Tools toolPanel);
public void hideTool()
{
NoparamDelegate hide = delegate (Tools toolPanel)
{
toolPanel.Visibility = Visibility.Hidden;
btnTool.Switch = false;
};
hide.Invoke(toolPanel);
} public void hideTool()
{
Dispatcher.Invoke(()=> {
toolPanel.Visibility = Visibility.Hidden;
btnTool.Switch = false;
});
}

在实际操作用,如果用Thread操作界面相关的代码,会出现错误:    调用线程必须为 STA,因为许多 UI 组件都需要

那么我们该如何处理呢?

1、委托实现

public delegate void NoParamDelegate();

//要实现的方法

public void Func()
 {

//使用ui元素

}

线程函数中做如此调用:  System.Windows.Application.Current.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,new NoParamDelegate(Func));

2、指定线程为STA

Thread NetServer = new Thread(new ThreadStart(NetServerThreadFunc));
 NetServer .SetApartmentState(ApartmentState.STA);
 NetServer .IsBackground = true;

 NetServer.Start();

 线程函数中做如此调用:

System.Windows.Threading.Dispatcher.Run();

C#中的异步和同步的更多相关文章

  1. 简单的node爬虫练手,循环中的异步转同步

    简单的node爬虫练手,循环中的异步转同步 转载:https://blog.csdn.net/qq_24504525/article/details/77856989 看到网上一些基于node做的爬虫 ...

  2. js中的异步与同步,解决由异步引起的问题

    之前在项目中遇到过好多次因为异步引起的变量没有值,所以意识到了认识js中同步与异步机制的重要性 在单线程的js中,异步代码会被放入一个事件队列,等到所有其他代码执行后再执行,而不会阻塞线程. 下面是j ...

  3. ajax中的async属性值之同步和异步及同步和异步区别

    jquery中ajax方法有个属性async用于控制同步和异步,默认是true,即ajax请求默认是异步请求,有时项目中会用到AJAX同步.这个同步的意思是当JS代码加载到当前AJAX的时候会把页面里 ...

  4. 深入理解 JS 引擎执行机制(同步执行、异步执行以及同步中的异步执行)

    首先明确两点: 1.JS 执行机制是单线程. 2.JS的Event loop是JS的执行机制,深入了解Event loop,就等于深入了解JS引擎的执行. 单线程执行带来什么问题? 在JS执行中都是单 ...

  5. ASP.NET MVC EF 中使用异步控制器

    最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精   为什么使用异步操作/线程池 ASP.NET MVC ...

  6. NodeJS中的异步I/O、事件驱动

    nodejs的主要特点是单线程.异步I/O.事件驱动.让我们先大概了解一下这些名词的意思. 单线程 单线程是任务按照顺序执行的,并且每次只执行一个任务,只有前面的任务执行完成以后,后面的任务才执行.在 ...

  7. C#中的线程一(委托中的异步)

    C#中的线程一(委托中的异步) 一.同步委托 我们平时所用的委托以同步居多,我们编写一个方法和相关委托进行演示: publicdelegatevoid DoSomethingDelegate(stri ...

  8. 看stackoverflow大牛如何回答何时在ASP.NET中使用异步控制器?

    转载自博客园:http://farb.cnblogs.com/ 今天无意中看到stackoverflow上一个很好的问答,个人觉得很有价值,所以翻译过来和大家共享!希望大家能相互交流. 在ASP.NE ...

  9. 入门级的按键驱动——按键驱动笔记之poll机制-异步通知-同步互斥阻塞-定时器防抖

    文章对应视频的第12课,第5.6.7.8节. 在这之前还有查询方式的驱动编写,中断方式的驱动编写,这篇文章中暂时没有这些类容.但这篇文章是以这些为基础写的,前面的内容有空补上. 按键驱动——按下按键, ...

随机推荐

  1. STL lower_bound upper_bound binary-search

    STL中的二分查找——lower_bound .upper_bound .binary_search 二分查找很简单,原理就不说了.STL中关于二分查找的函数有三个lower_bound .upper ...

  2. Java基础(38):Calendar类的应用(优于Date类)

    Calendar 类的应用 Date 类最主要的作用就是获得当前时间,同时这个类里面也具有设置时间以及一些其他的功能,但是由于本身设计的问题,这些方法却遭到众多批评,不建议使用,更推荐使用 Calen ...

  3. javaIO整理

    写在前面:本文章基本覆盖了java IO的全部内容,java新IO没有涉及,因为我想和这个分开,以突出那个的重要性,新IO哪一篇文章还没有开始写,估计很快就能和大家见面.照旧,文章依旧以例子为主,因为 ...

  4. linux挂接U盘

    挂接U盘fdisk -lDisk /dev/sdd: 131 MB, 131072000 bytes/dev/sdd1 * 1 889 127983+ b Win95 FAT32#mkdir -p / ...

  5. 刚刚学了循环,1到n的求和与阶乘

    //求和 int a = Convert.ToInt32(Console.ReadLine()); int c = 0; for (int b = 0; b <= a; b++) { c = c ...

  6. oracle查询表的索引

    select * from user_indexes where table_name='表名'; select * from user_ind_columns where index_name='索 ...

  7. 夺命雷公狗---node.js---7fs模块初步

    目录结构如下所示: /** * Created by leigood on 2016/8/13. */ var http = require("http"); var fs = r ...

  8. DFT basics

    DFT测试中,最重要的部分还是sequential circuit的内部状态的测试. 起初ad hoc的方法用来提高testability,可以提高局部的coverage,但并不是一个系统性的方法. ...

  9. 【crunch bang】中文美化

    原文连接:http://edyfox.codecarver.org/html/debian_testing_chinese.html 中文字体美化是个很讨厌的事情,无数初学者在这里面浪费了无数时间,做 ...

  10. php导出word格式数据的代码

    <?php /** * 生成word文档的类 * by www.jbxue.com */ class word {          function start()     {         ...