《C#网络应用编程(第3版)(工业和信息化部“十二五”规划教材) (普通高等学校计算机教育“十二五”规划教材)[精品]》-想法

本文详细介绍了C#中的网络编程,包括System.Net.Sockets命名空间中的TcpClient、TcpListener和UdpClient类,以及套接字的流式、数据报和原始类型。探讨了IP地址的分类、子网掩码、端口的作用,以及IPv4和IPv6的区别。同时,讲解了网络应用程序中使用端口、子网掩码、IPHostEntry和IPAddress类的重要性。此外,文章还涉及到了网络接口的检测、网络适配器信息以及网络进程的管理和监控。最后,讨论了WCF服务的配置、绑定、消息编码,以及利用WCF实现HTTP和TCP应用的编程方法。
摘要由CSDN通过智能技术生成

2016-08-02
原文:对于需要侦听网络并发送请求的网络应用程序而言,System.Net.Sockets 命名空间提供了TcpClient类、TcpListener类和UdpClient类。这些类用传统技术封装了不同传输协议建立连接的实现细节,提供了多种传输数据的操作方法。另外,当需要在套接字级别进行控制时,还可以直接用该命名空间下的Socket类来实现。




2016-08-02
原文:套接字有3种不同的类型:流式套接字、数据报套接字和原始套接字。流式套接字用来实现面向连接的TCP通信,数据报套接字实现无连接的UDP通信,原始套接字实现IP数据包通信。这3种类型的套接字均可以用System.Net.Sockets命名空间下的Socket类来实现。 编写基于TCP和UDP的应用程序时,既可以使用对套接字进一步封装后的TcpListener类、TcpClient类或UdpClient类,也可以直接用Socket类来实现。而编写自定义的新网络协议程序时,则只能用Socket类来实现,而且这个实现工作量是巨大的。




2016-08-02
原文:IP连接领域有两种通信类型:面向连接的(Connection-Oriented)和无连接的(Connectionless)。在面向连接的套接字中,使用TCP来建立两个IP地址端点之间的会话。一旦建立了这种连接,就可以在设备之间进行可靠的数据传输。 对于网络应用程序而言,在System.Net.Sockets命名空间下,除了套接字以外,.NET框架还提供了TcpClient类和TcpListener类。这些类封装了不同传输协议建立连接的细节,提供了多种传输数据的操作方法。




2016-08-02
原文:除了TCP、UDP以外,还有用传统技术实现的HTTP应用编程、FTP应用编程、SMTP与POP3应用编程以及P2P应用编程等




2016-08-02
原文:使用IP地址的点分十进制表示法,Internet地址空间又划分为5类,具体如下。 A类:0.x.x.x~127.x.x.x (32位二进制最高位为 0) B类:128.x.x.x~191.x.x.x (32位二进制最高2位为10) C类:192.x.x.x~223.x.x.x (32位二进制最高3位为110) D类:224.x.x.x~239.x.x.x (32位二进制最高4位为1110) E类:240.x.x.x~255.x.x.x (32位二进制最高5位为11110) 在这5类IP地址中,A类IP地址由1字节的网络地址和3字节的主机地址组成,主要用于网内主机数达1600多万台的大型网络。




2016-08-02
原文:注意,A类中有一个特殊的IP地址,即127.0.0.1,该地址专用于本机回路测试。 B类IP地址由2字节的网络地址和2字节的主机地址组成,适用于中等规模的网络,每个网络所能容纳的计算机数大约为6万多台。 C类IP地址由3字节的网络地址和1字节的主机地址组成,适用于小规模的局域网,每个网内最多只能包含254台计算机。 D类地址属于一种特殊类型的IP地址,TCP/IP规定,凡IP地址中的第一字节以“lll0”开始的地址都叫多点广播地址。因此,任何第一字节大于223小于240的IP地址都是多点广播地址。 E类地址作为特殊用途备用。




2016-08-02
原文:在这些网络分类中,每类网络又可以与后面的一个或多个字节组合,进一步分成不同的网络,称为子网。每个子网必须用一个公共的网址把它与该类网络中的其他子网分开。 为了识别IP地址的网络部分,又为特定的子网定义了子网掩码。子网掩码用于屏蔽IP地址的一部分以区别网络标识和主机标识,它是判断任意两台计算机的IP地址是否属于同一子网的依据,并说明该IP地址是在局域网上,还是在远程网上。 把所有的网络位(二进制)用1来标识,主机位用0来标识,就得到了子网掩码。 IP 地址与子网掩码的关系可以简单地理解为:两台计算机各自的 IP 地址与子网掩码进行二进制“与”运算后,如果得出的结果是相同的,则说明这两台计算机处于同一个子网,否则就是处于不同的子网上。 假设子网掩码为255.255.255.0,转化为二进制为11111111.11111111.11111111.00000000,则IP地址和子网掩码进行二进制“与”运算后,前3字节构成网络标示(子网号),第4字节为0。例如,对于IP地址192.168.1.X,可以将子网掩码设置为255.255.255.0,则该子网内所有的IPv4地址为 192.168.1.0、




2016-08-02
原文:192.168.1.1、192.168.1.2、…、192.168.1.254、192.168.1.255 (2)IPv6编址方案。第2种IP地址编址方案是IPv6编址方案。在这种编址方案中,每个IP地址有16字节(128位二进制数),其完整格式用8段十六进制表示,各段之间用冒号分隔。为了简化表示形式,每段中前面的0可以省略。另外,连续的0可省略为“::”,但只能出现一次。例如: 1080:0:0:0:8:800:200C:417A简写为 1080::8:800:200C:417A FF01:0:0:0:0:0:0:101简写为FF01::101




2016-08-02
原文:0:0:0:0:0:0:0:1简写为::1 0:0:0:0:0:0:0:0简写为:: 本机回环地址:IPv4为127.0.0.1,IPv6为::1 另外,IPv6没有定义广播地址,其功能由多播地址替代。




2016-08-02
原文:从表面上看,好像知道了远程主机的IP地址,本机就能够和远程主机相互通信。其实真正相互完成通信功能的不是两台计算机,而是两台计算机上的进程。或者说,IP地址仅仅能够识别到某台主机,而不能识别该主机上的进程。如果要进一步识别是哪个进程,还需要引入新的地址空间,这就是端口(Port)。 在网络通信技术中,端口有两种含义:一是指物理意义上的端口,比如,ADSL Modem、集线器、交换机、路由器上连接其他网络设备的接口,如RJ-45端口、SC端口等;二是指逻辑意义上的端口,即进程标识,端口号的范围从0到65535,比如用于HTTP的80端口,用于FTP的21端口等。




2016-08-02
原文:由于端口地址用两字节二进制数来表示,因此,可用端口地址的范围是十进制的0~65535。另外,由于1000以内的端口号大多被标准协议所占用,所以程序中可以自由使用的端口号一般都使用大于1000的值。




2016-08-05
原文:在编写各种复杂的网络应用程序之前,需要首先掌握几个最基本的类:提供网际协议IP地址的IPAddress类,包含IP地址和端口号的IPEndPoint类和为Internet或Intranet主机提供信息容器的IPHostEntry类。




2016-08-05
原文:1.IPAddress类 System.Net命名空间下的IPAddress类提供了对IP地址的转换和处理功能。一般用IPAddress类提供的静态Parse方法将IP地址字符串转换为IPAddress的实例。例如: try { IPAddress ip = IPAddress.Parse("143.24.20.36"); } catch { MessageBox.Show("请输入正确的IP地址!"); } 如果提供的IP地址字符串格式不正确,调用Parse方法时会出现异常。 另外,利用该实例的AddressFamily属性可判断该IP地址是IPv6还是IPv4。例如: IPAddress ip = IPAddress.Parse("::1");




2016-08-05
原文:if (ip.AddressFamily == AddressFamily.InterNetworkV6) { MessageBox.Show("这是IPv6地址"); } IPAddress类还提供了7个只读字段,分别代表程序中使用的特殊IP地址。




2016-10-29
原文:NetworkInterface类位于System.Net.NetworkInformation命名空间下,利用它可以方便地检测本机有多少个网络适配器、哪些网络连接可用,并可获取某个网络适配器的型号、MAC(Media Access Control, 介质访问控制)地址和速度等信息。




2016-10-29
原文:NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces( );




2016-10-29
原文:IPInterfaceProperties类提供了检测IPv4和IPv6的网络适配器地址信息,利用该类可检测本机所有网络适配器支持的各种地址,如DNS服务器的IP地址、网关地址以及多路广播地址等。




2016-10-29
原文:byte[] macBytes = adapter.GetPhysicalAddress().GetAddressBytes(); sb.AppendLine("MAC地址:" + BitConverter.ToString(macBytes));




2016-10-29
原文:如果希望统计本机接收和发送数据的情况,可利用 System.Net.NetworkInformation 命名空间下的IPGlobalProperties类来实现。该类提供了本地计算机网络连接和通信统计数据的信息。例如,接收到的数据包个数、丢弃的数据包个数等。




2016-10-29
原文:Ribbon控件属于高级控件,默认没有放到工具箱中,因此,使用该控件前,首先需要通过添加引用的办法将其添加到项目中




2016-10-29
原文:Ribbon 控件主要包括以下子项:QuickAccessToolBar(快速访问工具栏)、Application Menu (应用程序菜单)、RibbonTab(选项卡)。另外,在QuickAccessToolBar和RibbonTab子项内,除了可以使用一般的WPF控件外,最常见的做法是在该控件的子项中包含Ribbon专用的子控件。




2016-10-29
原文:修改Ribbon的ShowQuickAccessToolBarOnTop属性,可控制快速访问工具栏显示的位置(控制显示在功能区的上部还是下部)。修改RibbonApplicationMenu的Visibility属性,可控制菜单的可见形式(显示、隐藏、折叠)。 如果希望将快速访问工具栏作为窗口的标题栏,只需要将根元素(默认是Window元素)改为RibbonWindow即可。但这并不是必需的,开发人员可根据需要决定是否这样做。




2016-10-29
原文:或触笔。 WPF在System.Windows.Ink命名空间下提供了与数字墨迹相关的类,利用这些类,可方便地实现动态绘图和编辑功能。




2016-10-29
原文:在 System.Windows.Controls 命名空间下,有一个 InkCanvas 控件(或者叫 InkCanvas 类、InkCanvas元素),该控件实现了墨迹的收集、复制、选择、显示和输入等功能。利用InkCanvas,可以让用户修改或删除现有的Stroke对象,同时还可以将其他控件添加到InkCanvas中。




2016-10-29
原文:InkCanvas类的常用属性如下。 1.DefaultDrawingAttributes属性 DefaultDrawingAttributes 属性用于获取或设置 InkCanvas 中新笔画的绘制特性(DrawingAttributes 对象)。该属性的可选值有:Color(笔画颜色)、Width(触笔宽度)、Height (触笔高度)、StylusTip(触笔形状,圆形或者矩形)、IsHighlighter(触笔是否像荧光笔)、FitToCurve (是否用贝塞尔曲线平滑法来呈现笔画)、IgnorePressure(笔画粗细是否随压力自动改变)。 2.EditingMode属性 EditingMode 属性指定了触笔、手指、鼠标等设备与 InkCanvas 交互的模式,属性的值用InkCanvasEditingMode枚举来表示,默认值为Ink。可选的枚举值有:Ink(接收墨迹)、GestureOnly (只响应笔势或手势但不接收墨迹)、None(不执行任何操作)、Select(用套索方式以及用触笔与墨迹相交的方式选择墨迹)、EraseByPoint(当触笔与墨迹相交时清除相交处的墨迹)、EraseByStroke (当触笔与墨迹相交时清除整个笔画)。




2016-10-29
原文:触点用System.Windows.Ink命名空间下的StylusPoint结构来表示,该结构的属性如下。 ● X、Y:获取或设置StylusPoint的X坐标值或者Y坐标值。 ● PressureFactor属性:获取或设置触笔施加于图面设备的压力大小。 ● Description属性:指定StylusPoint中的StylusPointDescription包含哪些属性。默认情况下,所有StylusPoint对象均包含(x, y)坐标以及触点压力属性。 实现高级的墨迹绘制功能时,可考虑使用PressureFactor属性和Description属性。




2016-10-29
原文:4.触点压力(PressureFactor) System.Windows.Ink命名空间下的PressureFactor类表示当触笔或手指按压在图面设备上时按压力量的大小,简称触点压力。用鼠标模拟时,可通过鼠标移动的快慢来表示,移动越快,表示触点压力越小;移动越慢,表示触点压力越大。 触点压力最小为0.0,最大为1.0,默认值为0.5。




2016-10-31
原文:Guid结构有多种构造函数,下面是其中的一种构造函数语法。 public Guid( int a,  //4字节 short b, //2字节 short c, //2字节 byte[] d //8字节 ) 该构造函数中参数a、b、c、d所占的字节数分别为:4、2、2、8。




2016-10-31
原文:一般用Guid的静态NewGuid方法自动获取新的GUID。例如: Guid id = Guid.NewGuid(); 这种方式能确保每次创建的id都不相同。这样一来,绘图时我们就不需要自己去创建和维护每个对象的ID号了。




2016-10-31
原文:自定义墨迹画板最简洁的办法就是让其继承自InkCanvas类。




2016-10-31
原文:一个 InkCanvas 可以具有一个或多个动态呈现的对象(DynamicRenderer)。在自定义的墨迹画板中,我们只需要将多个DynamicRenderer对象分别添加到StylusPlugIns属性中,再将其赋值给DynamicRenderer属性,即可将其添加到自定义的InkCanvas中。 DynamicRenderer对象是一个特殊的StylusPlugIns对象,在WPF应用程序中,使用InkCanvas或者使用继承自 InkCanvas 类的自定义墨迹控件,不需要显式声明 StylusPlugIns,只需要设计从DynamicRenderer继承的类,即可实现动态的即时呈现。




2016-10-31
原文:有了自定义的墨迹画板后,再利用InkCanvas的DynamicRenderer属性,就可以立即呈现出用户在图面上绘制的各种墨迹形状。 制作自定义墨迹画板的主要设计步骤如下。 ● 创建一个从InkCanvas派生的类。 ● 将自定义的DynamicRenderer分配给InkCanvas.DynamicRenderer属性。 ● 重写 OnStrokeCollected 方法。在此方法中,移除已添加到 InkCanvas 中的原始笔画,然后创建一个自定义笔画,将其添加到 Strokes 属性中,最后再使用包含该自定义笔画的新InkCanvasStrokeCollectedEventArgs调用基类相应的方法。




2016-10-31
原文:在操作系统级别的管理中,利用 Process 类可启动、停止本机或远程进程。进程所执行的程序(.exe文件、.dll文件、桌面快捷方式)可以用各种语言(如C#、Java、C++等)来编写。




2016-10-31
原文:硬件实现的角度来说,对于早期的单核处理器,可将线程看作是操作系统分配处理器时间片的基本执行单元;对于目前的多核处理器,可将线程看作是在每个内核上独立执行的代码段。




2016-10-31
原文:System.Diagnostics命名空间下的Process类提供了在操作系统级别对进程进行管理的各种属性和方法。利用 Process 类,可以启动和停止本机进程,获取或设置进程优先级,确定进程是否响应,是否已经退出,以及获取系统正在运行的所有进程列表和各进程的资源占用情况等。同时也可以利用它查询远程计算机上进程的相关信息,包括进程内的线程集合、加载的模块(.dll 文件和.exe文件)和性能信息(如进程当前使用的内存量等)。




2016-10-31
原文:1.启动进程 如果希望启动某个进程,首先需要创建 Process类的一个实例,并通过 StartInfo 属性指定要运行的应用程序名称以及传递的参数,然后调用该实例的Start方法启动该进程。另外,如果进程带有图形用户界面,还可以用ProcessWindowStyle枚举指定启动进程时如何显示窗口。可选的枚举值有:Normal(正常窗口)、Hidden(隐藏窗口)、Minimized(最小化窗口)和Maximized(最大化窗口)。例如: Process myProcess = new Process(); myProcess.StartInfo.FileName = "Notepad.exe"; //准备执行记事本Notepad.exe myProcess.StartInfo.Arguments = "Test1.txt"; //创建或打开的文档为Test1.txt myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal; myProcess.Start();




2016-10-31
原文:2.停止进程 有两种停止进程实例的方法:Kill方法和CloseMainWindow方法。前者用于强行终止进程,后者只是“请求”终止进程。




2016-10-31
原文:(1)Kill方法和CloseMainWindow方法。 Process实例的Kill方法是终止没有图形化界面进程的唯一方法。由于该方法使进程非正常终止,因此有可能会丢失没有保存的数据,所以一般只在必要时才使用该方法。另外,由于Kill方法是异步执行的,因此在调用 Kill 方法后,还要调用 WaitForExit 方法等待进程退出,或者检查HasExited属性以确定进程是否已经退出。 Process 实例的 CloseMainWindow 方法通过向进程的主窗口发送关闭消息来关闭进程,其行为与用户在界面中单击【关闭】按钮命令的效果相同。这样可使目标程序有机会在清除操作中提示用户保存任何没有保存的数据。如果成功发送了关闭消息,则返回 true;如果关联进程没有主窗口或禁用了主窗口(例如,当前正在显示模式对话框),则返回false。




2016-10-31
原文:只能对本机进程实例调用Kill方法或CloseMainWindow方法,无法用这些方法控制远程计算机上的进程。对于远程计算机上的进程,只能查看进程的信息。




2016-10-31
原文:Process实例的HasExited属性用于判断启动的进程是否已停止运行。如果与Process关联的进程已关闭则返回true,否则返回false。当进程退出时,操作系统将释放进程占用的内存,但仍会保留有关进程的管理信息,例如句柄、退出代码(ExitCode属性)和退出时间(ExitTime属性)。这些属性都是自动填充的,即使用户通过选择界面中的【关闭】命令关闭进程,系统也会自动更新HasExited属性以及ExitTime属性的值。如果希望确保退出应用程序时让Process实例启动的所有进程都关闭,这两个属性是很有用的。




2016-10-31
原文:WaitForInputIdle方法。 Process实例的WaitForInputIdle方法仅适用于具有用户界面的进程,它可以使Process等待关联进程进入空闲状态。如果关联进程已经达到空闲状态,则返回true;否则返回false。例如: Process myProcess = Process.Start("Notepad"); myProcess.WaitForInputIdle(); 此状态很有用,比如某个应用程序需要等待启动的进程完成创建其主窗口,然后才能与该窗口通信。这种情况下,就需要调用WaitForInputIdle方法。




2016-10-31
原文:WaitForExit方法。 Process实例的WaitForExit方法用于设置等待关联进程退出的时间,并在该段时间结束前或该进程退出前,阻止当前线程执行。




2016-10-31
原文:Process 实例的 ExitCode 属性用于获取关联进程终止时指定的值,该属性值为零表示成功退出,非零表示错误编号。ExitTime属性用于获取关联进程退出的时间。 这两个属性只能在HasExited属性为True时才能检测。




2016-10-31
原文:EnableRaisingEvents属性。 Process实例的 EnableRaisingEvents 属性用于获取或设置在进程终止时是否应引发 Exited 事件,如果关联的进程终止(通过退出或者调用Kill)时引发Exited事件则为true,否则为false,默认为false。 如果希望在进程退出后获得通知,可将与该进程关联的组件的EnableRaisingEvents属性设置为true,然后在Exited事件中处理进程退出后的操作。另外,一般在异步操作中将该属性设置为true。如果强制同步等待Exited事件发生,应该用WaitForExit方法。




2016-10-31
原文:/获取本机所有进程 Process[] myProcesses = Process.GetProcesses( ); //获取网络上远程计算机的所有进程。参数可以是远程计算机名,也可以是远程计算机的IP地址 Process[] myProcesses = Process.GetProcesses("192.168.0.1");




2016-10-31
原文:这里需要注意一点,使用GetProcesses方法时,如果所获取的进程不是用Start方法启动的,则该进程的 StartInfo属性将不包含该进程启动时使用的参数,此时应该用数组中每个 Process对象的MainModule属性获取相关信息。




2016-10-31
原文://获取本机指定名称的进程 Process[] myProcesses1 = Process.GetProcessesByName("MyExeFile"); //不要带扩展名 //获取远程计算机上指定名称的进程,参数1是进程名,参数2是远程计算机的名称或IP地址 Process[] myProcesses2 = Process.GetProcessesByName("Notpad", "Server1");




2016-11-01
原文:只有当属于某个进程的所有前台线程都终止后,公共语言运行库才会结束该进程,而且所有属于该进程的后台线程也都会立即停止,而不管其后台工作是否完成。




2016-11-01
原文:具体来说,用Thread对象创建的线程默认都是前台线程,在托管线程池中执行的线程默认都是后台线程。另外,从非托管代码进入托管执行环境的所有线程也都被自动标记为后台线程。




2016-11-01
原文:● IsBackground属性:获取或设置一个值,该值指示某个线程是否在后台执行。如果在后台执行则为true;否则为false。 ● IsThreadPoolThread属性:获取一个值,该值指示线程是否在托管线程池中执行。如果此线程在托管线程池中执行则为true,否则为false。 另外,为了使主线程能及时对用户操作的界面进行响应,也可以将辅助线程作为“后台”任务来执行,即将其设置为后台线程。比如用一个单独的线程监视某些活动,最好将其IsBackground属性设置为true使其成为后台线程,这样做的目的是为了不让该线程影响UI操作和进程的正常终止。




2016-11-01
原文:通过Thread对象可创建一个单独的线程,常用形式为 Thread t = new Thread(<方法名>); 该语句的意思是创建一个线程t,并自动通过相应的委托执行用“<方法名>”指定的方法。




2016-11-01
原文:线程是通过委托来实现的,至于使用哪种委托,要看定义的方法是否带参数。如果定义的方法不带参数,就自动用 ThreadStart 类型的委托调用该方法;如果带参数,则自动用ParameterizedThreadStart类型的委托调用该方法。




2016-11-01
原文:面的代码创建了2个线程。 Thread t1 = new Thread(Method1); Thread t2 = new Thread(Method2); ...... public void Method1(){……} public void Method2(object obj){……}




2016-11-01
原文:上面这段代码和下面的代码是等价的: Thread t1 = new Thread(new ThreadStart(Method1)); Thread t2 = new Thread(new ParameterizedThreadStart(Method2)); ...... public void Method1(){......} public void Method2(object obj){......}




2016-11-01
原文:用 Thread 创建的线程默认为前台线程,如果希望将其作为后台线程,可将线程对象的IsBackground属性设置为true。例如: Thread myThread = new Thread(Method1); myThread.IsBackground = true; 创建线程并设置让其在前台运行还是后台运行后,即可对线程进行操作,包括启动、停止、休眠、合并等。




2016-11-01
原文:启动线程 用Thread创建线程的实例后,即可调用该实例的Start方法启动该线程。例如: t1.Start(); //调用不带参数的方法 t2.Start("MyString"); //调用带参数的方法 在当前线程中调用Start方法启动另一个线程后,当前线程会继续执行其后面的代码。 当将方法作为一个单独的线程执行时,如果方法带有参数,只能在启动线程时传递实参,而且定义该方法的参数只能是一个Object类型。如果希望传递多个参数,可以先将这些参数封装到一个类中,然后传递该类的实例,再在线程中通过该类的实例访问相应的数据。




2016-11-01
原文:线程启动后,当不需要某个线程继续执行的时候,有两种终止线程的方法。 第1种方法是先设置一个修饰符为volatile的布尔型的字段表示是否需要正常结束该线程,称为终止线程。例如: public volatile bool shouldStop; 线程中可循环判断该布尔值,以确定是否退出当前的线程。在其他线程中,可通过修改该布尔值通知是否希望终止该线程。这是正常结束线程比较好的方法,实际应用中一般使用这种方法。




2016-11-01
原文:第2种方法是在其他线程中调用Thread实例的Abort方法终止当前线程,该方法的最终效果是强行终止该线程的执行,属于非正常终止的情况,称为取消线程的执行(不是指销毁线程)。但这种方式可能会导致某个工作执行到一半就结束了。




2016-11-01
原文:Thread.Sleep(1000); //当前线程暂停1s




2016-11-01
原文:创建线程时,默认优先级为Normal。如果想让一些重要的线程优先执行,可以使用下面的方法为其赋予较高的优先级。 Thread t1 = new Thread(MethodName); t1.priority = ThreadPriority.AboveNormal




2016-11-01
原文:注意,当把某线程的优先级设置为最高时,在该线程结束前,其他所有线程都将无法获得执行的机会,这会导致界面看起来像“死机”一样,所以使用最高优先级时要特别小心。除非遇到必须马上处理的任务,否则不要使用最高优先级。




2016-11-01
原文:线程池(ThreadPool类) 线程池是在后台执行任务的线程集合,它与Thread的主要区别是线程池中的线程是有关联的(如当某个线程无法进入线程池执行时先将其放入等待队列,自动决定用哪个处理器执行线程池中的某个线程,自动调节这些线程执行时的负载平衡问题等)。另外,线程池总是在后台异步处理请求的任务,而不会占用主线程,也不会延迟主线程中后续请求的处理。




2016-11-01
原文:ThreadPool类提供了对线程池的操作,如向线程池中发送工作项、处理异步I/O、利用委托自动调度等待的线程、处理专用的计时行为等。 1.线程池的基本特征 托管线程池有如下基本特征。 ● 托管线程池中的线程都是后台线程。 ● 添加到线程池中的任务不一定会立即执行。如果所有线程都繁忙,则新添加到线程池的任务将放入等待队列中,直到有线程可用时才能够得到处理。 ● 线程池可自动重用已创建过的线程。一旦池中的某个线程完成任务,它将返回到等待线程队列中,等待被再次使用,而不是直接销毁它。这种重用技术使应用程序可避免为每个任务创建新线程引起的资源和时间消耗。 ● 开发人员可设置线程池的最大线程数。从.NET 框架 4.0 开始,线程池的默认大小由虚拟地址空间的大小等多个因素决定。而早期版本的.NET框架则是直接规定一个默认的最大线程数,无法充分利用线程池的执行效率。 ● 从.NET框架4.0开始,线程池中的线程都是利用多核处理技术来实现的。




2016-11-01
原文:向线程池中添加工作项 在传统的编程模型中,开发人员一般是直接用ThreadPool.QueueUserWorkItem方法向线程池中添加工作项。例如: ThreadPool.QueueUserWorkItem(new WaitCallback(Method1)); ThreadPool.QueueUserWorkItem(new WaitCallback(Method2)); ThreadPool只提供了一些静态方法,不能通过创建该类的实例来使用线程池。




2016-11-02
原文:(1)用volatile修饰符锁定公共或私有字段。 为了适应单处理器或者多处理器对共享字段的高效访问,C#提供了一个 volatile 修饰符,利用该修饰符可直接访问内存中的字段,而不是将字段缓存在某个处理器的寄存器中。这样做的好处是所有处理器都可以访问该字段最新的值。例如: private static volatile bool isStop = false; public static bool IsStop { get { return isStop; } set { isStop = value; } }




2016-11-02
原文:(2)用Interlocked类提供的静态方法锁定局部变量。 System.Threading.Interlocked类通过加锁和解锁提供了原子级别的静态操作方法,对并行执行过程中的某个局部变量进行操作时,可采用这种办法实现同步。例如: int num = 0; Interlocked.Increment(ref num); //将num的值加1 Interlocked.Decrement(ref num); //将num的值减1 锁定局部变量的另一种实现方式是直接用C#提供的lock语句将包含局部变量的代码块锁定,退出被锁定的代码块后会自动解锁。




2016-11-02
原文:(3)用lock语句锁定代码块。 为了在多线程应用程序中实现不同线程同时执行某个代码块的功能,C#提供了一个 lock 语句,该语句能确保当一个线程完成执行代码块之前,不会被其他线程中断。被锁定的代码块称为临界区。 lock语句的实现原理是进入临界区之前先锁定某个私有对象(声明为private的对象),然后再执行临界区中的代码,当代码块中的语句执行完毕后,再自动解除该锁。例如: private List<int> list = new List<int>( ); ...... lock(list) { ...... //对list进行操作 } 如果锁定的代码段中包含多个需要同步的字段或者多个局部变量,可先定义一个私有字段lockedObj,通过一次性锁定该私有字段实现多个变量的同步操作。例如: private Object lockedObj = new Object ( );




2016-11-02
原文:lock(lockedObj) { ...... } 提供给 lock 的对象可以是任意类型的实例,但不允许锁定类型本身,也不允许锁定声明为public的对象,否则将会使lock语句无法控制,从而引发一系列问题。




2016-11-02
原文:如果开发人员使用的不是C#语言(比如C++等),则只能用.NET框架提供的类来完成各种不同情况下的同步功能(例如Monitor类、Mutex类、SpinLock类、ReaderWriterLockSlim类、Semaphore类、WaitHandle类、EventWaitHandle类等),只是这些类分别适用于不同的情况,用起来没有C#提供的volatile修饰符和lock语句简单而已。如果读者希望深入理解相关概念和原理(类似操作系统课程中介绍的生产者消费者问题),以及在不同情况下应该如何分别处理死锁和争用情况的细节,可参考这些类提供的实现方式。




2016-11-03
原文:1.WPF调度器(Dispatcher) 不论是WPF应用程序还是WinForm应用程序,默认情况下,.NET框架都不允许在一个线程中直接访问另一个线程中的控件,这是因为如果有两个或多个线程同时访问某一控件,可能会使该控件进入一种不确定的状态,甚至可能出现死锁。 为了解决死锁以及异步执行过程中的同步问题,WPF中的每个元素(包括根元素)都有一个Dispatcher属性,Dispatcher会自动在线程池中按优先级对工作项进行排队和调度。通过该属性执行指定的委托,即可实现不同线程之间的交互而不会出现死锁问题。 要在后台线程中与用户界面交互,可以通过向WPF控件的Dispatcher注册工作项来完成。注册工作项的常用方法有两种:Invoke方法和InvokeAsync方法。这两个方法均通过调度器执行指定的委托来实现。例如: TextBlock1.Dispatcher.Invoke(...); TextBlock1.Dispatcher.InvokeAsync(...);




2016-11-03
原文:Invoke 方法是同步调用,即直到在线程池中实际执行完该委托它才返回。InvokeAsync 方法是异步调用,调用该方法后将立即返回到调用的语句,然后继续执行该语句后面的代码。 Dispatcher.Invoke方法的重载形式非常多,常用的重载形式有: Invoke(

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赤龙绕月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值