C#线程池用法

C#线程池用法

C#编程语言中,使用线程池可以并行地处理工作,当强制线程和更新进度条时,会使用内建架构的ThreadPool类,为批处理使用多核结构,这里我们来看在C#编程语言中一些关于来自System.ThreadingThreadPool的用法的例子

介绍

       .NET Framework提供了包含ThreadPool类的System.Threading 空间,这是一个可直接访问的静态类,该类对线程池是必不可少的。它是公共“线程池”设计样式的实现。对于后台运行许多各不相同的任务是有用的。对于单个的后台线种而言有更好的选项。

       线程的最大数量。这是完全无须知道的。在.NETThreadPool的所有要点是它自己在内部管理线程池中线程。多核机器将比以往的机器有更多的线程。微软如此陈述“线程池通常有一个线程的最大数量,如果所有的线程都忙,增加的任务被放置在队列中直到它们能被服务,才能作为可用的线程。”

用法位置

        线程池类型能被用于服务器和批处理应用程序中,线程池有更廉价的得到线程的内部逻辑,因为当需要时这些线程已被形成和刚好“连接”,所以线程池风格代码被用在服务器上。

        MSDN表述:“线程池经常用在服务器应用程序中,每一个新进来的需求被分配给一个线程池中的线程,这样该需求能被异步的执行,没有阻碍主线程或推迟后继需求的处理。”

MSDN 参考

ThreadPool  VS  BackgroundWorker

        如果你正在使用Windows窗体,宁可使用BackgroundWorker来对付那些更简单的线程需求,BackgroundWorker在网络访问和其他一些简单的事情方面做得很好。但对于多处理器的批处理来说,你需要ThreadPool。

BackgroundWorker 教程

当你的程序要批处理时,考虑线程池

当你的程序产生很多(3个以上)线程时,考虑线程池

当你的程序使用Windows窗体时,考虑后台执行。

线程要考虑的事 同样,如何使用线程的细节能帮助发现最好的代码。下面比较线程情形和哪个类是最好的。

   你需要一个额外的线程   使用后台执行

   你有许多短期的线程     使用线程池 

需求

       线程很重要,但对于那些不会花很长时间来执行且只做一件事情的大多数应用程序来说却并不重要的。线程对于界面可用性不是很重要的的应用程序而言也不是很重要,要尽量避免使用线程(译者注:比如进度条不是很重要的应用程序)。

连接方法

        可使用QueueUserWorkItem连接方法(methods)到线程池。方法要运行在线程上,则必须把它连接到QueueUserWorkItem。如何实现呢?必须使用WaitCallback。在MSDN中,WaitCallback被描述成当线程池执行时要被调用的委托回调方法,是回调它的参数的委托。

WaitCallback

        只需指定“new WaitCallback”语句作为ThreadPool.QueueUserWorkItem的第一个参数来使用WaitCallback.不需要任何其他的代码来使用这方法生效。

使用WaitCallback的例子

复制代码
void Example()

{

    // 连接 ProcessFile 方法到线程池.

    //注意: 'a' 是一个作为参数的对象

    ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessFile), a);

}

private void ProcessFile(object a)

{

    // 我被连接到线程池通过 WaitCallback.

}
复制代码

参数

        我们能通过定义一个特定的类并把一些重要的值放在类里面来使用参数,那么,方法接收了对象,就能通过对象向方法传递多个参数了。以下是一个早期的例子。

使用带参数QueueUserWorkItem 的例子

复制代码
//指定作为线程池方法的参数的类

class ThreadInfo

{

    public string FileName { get; set; }

    public int SelectedIndex { get; set; }

}

class Example

{

    public Example()

    {

// 声明一个新的参数对象

ThreadInfo threadInfo = new ThreadInfo();

threadInfo.FileName = "file.txt";

threadInfo.SelectedIndex = 3;

//发送自定义的对象到线程方法

ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessFile), threadInfo);

    }

    private void ProcessFile(object a)

    {

ThreadInfo threadInfo = a as ThreadInfo;

string fileName = threadInfo.FileName;

int index = thread.SelectedIndex;

    }

}
复制代码

        发生了什么事?我们发送两个值给这个线程化的ProcessFile方法,它需要知道文件名和选择索引,而我们在这个对象中把参数都发送了给它。

进度条

        能通过从设计器中右边的工具盒面板中增加Windows窗体控件到你的窗体程序来使用进度条并设置 progressBar1.Value, progressBar1.Minimum 和progressBar1.Maximum。 progressBar1.Value是最小值和最大值中间的位置,以下代码用来初始化进度条:

设置进度条的例子 

复制代码
//设置进度条的长度.

// 这里我们有6个单位来完成,所以6是最大值。

// 最小值通常是0

progressBar1.Maximum = 6; // 或其他数字

progressBar1.Minimum = 0;
复制代码

       进度条位置 你的进度条中的有颜色部分是当前值与最大值的百分比。所以,如果最大值是6,而值是3即表示做完了一半。

ProgressBar 例子 (Windows Forms)

在进度条中调用Invoke(援引)

        让我们看如何在进度条实例中使用Invoke方法。遗憾的是,你不能在辅助线程中访问Windows控件,因为UI线程是分离的,必须使用委托(delegate)Invoke到进度条。

请求Invoke(调用)的例子

复制代码
public partial class MainWindow : Form

{

// 这是运行在UI线程来更新条的委托

 public delegate void BarDelegate();

//该窗体的构造器(由Visual Studio自己产生)

    public MainWindow()

    {

InitializeComponent();

    }

//当按下按钮,启动一个新的线程

    private void button_Click(object sender, EventArgs e)

    {

// 设定进度条的长度.

progressBar1.Maximum = 6;

progressBar1.Minimum = 0;

// 给线程传递这些值.

ThreadInfo threadInfo = new ThreadInfo();

threadInfo.FileName = "file.txt";

threadInfo.SelectedIndex = 3;

ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessFile), threadInfo);

    }

// 运行在后台线程上的东西

 private void ProcessFile(object a)

    {

// (省略)

// 使用'a'做一些重要的事.

// 告诉UI 我们已经完成了.

try

{

    // 在窗体中调用委托 .

    this.Invoke(new BarDelegate(UpdateBar));

}

catch

{

           //当一些问题发生后我们能使程序恢复正常

}

    }

    //更新进度条.

    private void UpdateBar() 

    {

progressBar1.Value++;

if (progressBar1.Value == progressBar1.Maximum)

{

    // 结束了,进度条满了.

}

    }

}
复制代码

        委托语法 以上代码的开始处,可以看到声明 UpdateBar 的委托。它告诉Visual Studio C# 需要来使用这个作为对象的方法。

        更多需要的工作 以上程序演示了如何设定进度条的最大值和最小值,如何在工作完成后“Invoke”委托方法来增加进度条的大小。

在调试器中的线程

       这儿要显示如何在Visual Studio的调试器中查看线程。一旦你有一个运行的程序,你能采取这些措施来可视化你的线程。首先,以调试模式打开你的线程应用程序,一旦你的应用程序运行在调试器,告知它去做它的工作而且运行这些线程,通过绿色箭头运行调试器,当线程正在运行,在工具条中单击“pause"按钮。

       下一步 调试>窗口>线程.该菜单项将打开一个类似下图的窗口,你能看见有多少线程正在线程池中运行。

四个辅助线程 上图显示了共有10个线程,但只有四个辅助线程(Worker Thread)在程序中被分配给MainWindow.ProcessFile.

约束辅助线程

        如果你有一个双核或四核系统,你将考虑最多两个四个很费力的线程。我们能在运行的线程中保持一个_threadCount 字段并且跟踪它的数值。用这个线程计数字段,你将需要在C#语言中使用一个锁来避免造成这个字段读和写的错误,锁保护你的线程被其他线程所改变。

计数线程的例子

复制代码
// 锁住这个对象.

readonly object _countLock = new object();

private void ProcessFile(object argument)

{

// 约束辅助线程的数量

while (true)

    {

lock (_countLock)

{

    if (_threadCount < 4)

    {

// Start the processing

_threadCount++;

break;

    }

}

Thread.Sleep(50);

    }

    // Do work...

}
复制代码

        我们看到什么 以是代码是异步执行的方法。只有其他辅助线程少于4个时它才会工作。这对于一个四核机器是好的。请看描述锁声明的更多上下文的文章

Lock Statement

控制线程计数器

       你可以在ThreadPool上使用SetMinThreads 来在连发活动中提高吞吐量和性能。以下是关于可使用的最佳的最小线程数量的材料。

ThreadPool.SetMinThreads Method

总结

        我们了解了如何在C#程序中使用线程池来有效管理多个线程,在Windows 窗体应用程序的进度条和用户界面中能给人留很深印象并且也不难实现。然而,线程带来了很多的复杂性并导致漏洞,线程池是一个有用的简化,但它仍然是困难的。

 
 

unix/linux中图形界面那些事

 我们知道unix/linux刚开始的时候是没有图形界面的,随着时代的发展,排版、制图、多媒体应用越来越普遍了,这些需求都需要用到图形界面(Graphical User Interface)。为此,MIT在1984年开发出了X window system,X在字母表中是W(indows)的下一个字母,寓意“下一代GUI”的意思。目前为止,unix/linux上几乎所有的发行版都采用X window system来作为自己的图形界面,它已经成为事实上的unix/linux图形界面标准。

  X window system,又名X,X11(现在主要的X window system大都基于其第11个版本),是一个能够跨网络和操作系统平台的图形界面。开发者在开发x时就希望,这个窗口界面不要与硬件有强烈的相关性,这是因为如果与硬件的相关性高,那就等于开发一个操作系统了,如此一来其应用性就要受到限制。故此,x是一套软件体系,而不是操作系统中的组成部分,就像浏览器不是操作系统的组成部分一样(当然微软在与网景干仗时可不管这些)。

X的软件架构

  如上图所示,X使用服务器-客户端模型:每个需要显示图形界面的主机都要运行一个x server,它负责主机中各个与图形界面有关硬件设备的管理,如在显示器中显示输出,从鼠标、键盘接受输入等。同时与不同的客户端程序(x client)通信,x client指那些需要图形界面的应用程序,如浏览器、终端、视频播放器等。这里需要解释一下,这里的server,client术语是从应用的角度而不是以用户的角度来说的:X server利用自己对硬件的掌控为应用提供显示界面以及处理输入输出等服务,所以说它是服务器端,而各种应用需要使用x server提供的这些服务,他们就是客户端了。

  x server和x client之间所使用的通信协议对网络来说是透明的,所以client和server可以运行在相同机器上,也可以运行在不同机器上,甚至机器本身的硬件架构和操作系统也可以不一样(如windows上的xmanager就是一个x server,它可以远程连接linux上的主机为linux上的x client提供服务,有兴趣的童鞋可以试下)。

   说完了x的软件架构,下面我们就来说说x中其他几个概念。

1. X Display Manager(XDM)

  display manager,又称login manager,是linux在boot进程完成之后启动的一个用于用户身份认证的图形界面,相当于文本模式下启动时让我们输入用户名和密码的shell。比较常见的有GNOME的gdm,KDE的kdm等。

  

  display manager可以在本地也可以在远程主机上启动。如果在本地启动,display manager接下来会把x server也启动起来,这样就可以在开机时显示如上图所示的图形界面了。

  如果display manager已经在远程启动了,我们在本地需要连接到远程的display manager上去,这时x server就用使用XDMCP(X Display Manager Control Protocol)协议连接到远程的display manager,请求开启一个会话,这样在本地也就出现了如上图所示画面,如果身份认证通过,display manager就退居二线,剩下的就是本地的x server与远程的x client之间互相交流了:我们通过x server(键盘、鼠标等输入设备)把我们的要求发给x client(x client与display manager 运行在同一台机器上),x client运行得到结果并将结果返回给x server,x server再通过自己管理的输出设备如显示屏等把结果显示出来,如此种种可以参看下图。

  我们可以发现,在第二种情况下,x server就相当于图形化界面的telnet客户端,而display manager 相当于图形化界面的telnet服务端,不是么?:-)

2. GNOME,KDE......

  GNOME和KDE都是运行在unix/linux操作系统之上的一个桌面环境,其中GNOME是基于GTK+ toolkit的(KDE是基于Qt toolkit的),它个性化了自己的界面风格,非常容易辨认,而且由于界面比较nice,已经是最近桌面系统的主流,它主要包括两大类:
  1.GNOME桌面环境,它包括了一些图形用户界面的实现细则,和一些核心图形界面应用如浏览器等。
  2.GNOME开发平台,它是一个为linux桌面及移动图形应用开发者提供的扩展平台,包括相应库文件以及开发API等。
  上文所说的GDM就是GNOME的一部分,一旦GDM通过了身份认证请求,它就会启动GNOME为用户提供图形化界面了,当然我们也可以从文本模式中通过startx命令来启动GNOME。

 3. GNOME与X的区别与联系

  关于GNOME与X之间的关系,这里有一篇文章介绍的非常清楚,现摘抄一部分如下,我就不画蛇添足了:

X11 is the window systemGnome is a desktop environment. The difference is that Gnome works through X11. Gnome and X11 run on Linux, though, not Windows. 

Basically, X11 is what displays everything. It's the graphical shell that connects you to the operating system. None of the applications you run ever send anything directly to the screen - they need to tell X11 what they want to display and let it do the work for them. 

X11 draws and moves windows and responds to input from the keyboard and mouse. That's pretty much it. Everything else is taken care of by the desktop environment. What that means is that the look and feel of the windows and the way those windows behave are all decided by which desktop environment you're using (Gnome, KDE, XFCE, etc.). 

The desktop environments all have their own graphics libraries (reusable chunks of code) that they use, along with APIs (Application Programming Interfaces) which allow programmers to use those libraries when they create GUI applications. This way programmers don't have to recreate commonly used functions and elements from scratch, and the whole operating system has a more standardized look. 

参考链接:http://en.wikipedia.org/wiki/X_Window_System

     http://en.wikipedia.org/wiki/X_display_manager_(program_type)

     https://wiki.archlinux.org/index.php/Display_Manager

       https://wiki.debian.org/DisplayManager

     http://en.wikipedia.org/wiki/GNOME

     http://stackoverflow.com/questions/17251293/what-is-the-relationship-between-x11-and-gnome 

 
标签: 线程池
原文地址:https://www.cnblogs.com/Leo_wl/p/3405641.html