利用 Visual C# 创作简单的多线程组件(转载于MSDN)

visual|多线程

可以编写能同时执行多个任务的应用程序。此能力(称为“多线程处理”或“自由线程处理”)是设计处理器密集型且要求用户输入的组件的强大方法。计算工资表信息的组件就是一个可能利用多线程处理的组件示例。该组件可以在一个线程上处理用户输入到数据库的数据,而在另一个线程上执行频繁使用处理器的工资表计算。通过在不同的线程上运行这些进程,用户不必等到计算机完成计算,就可以输入其他数据。在本演练中,将创建一个简单的多线程组件,该组件可以同时执行若干个复杂计算。

创建项目
应用程序将包括单个窗体和一个组件。用户将输入值并指示该组件开始计算。然后,窗体将接收来自该组件的值,将其显示在标签控件中。该组件将执行频繁使用处理器的计算,并在完成后通知窗体。您将在组件中创建公共变量,用以保存从用户界面收到的值。同时,您还将在组件中实现一些方法,根据这些变量的值执行计算。

注意 尽管对于计算值的方法来说,函数通常更为可取,但不能在线程之间传递参数,也不能返回值。有很多向线程提供值和从线程接收值的简单方法。在本演示中,将通过更新公共变量将值返回到用户界面,当线程执行完毕后,使用事件来通知主程序。
创建窗体

创建新的“Windows 应用程序”项目。
将应用程序命名为 Calculations,并将 Form1.cs 重命名为 frmCalculations.cs。
该窗体将用作应用程序的主用户界面。

双击设计器上的窗体以打开代码编辑器。在“编辑”菜单中,选择“查找和替换”,然后选择“替换”。使用“全部替换”将 Form1 替换为 frmCalculations。
在“解决方案资源管理器”中,右击“frmCalculations.cs”并选择“视图设计器”。设计器打开。
向窗体中添加 5 个 Label 控件、4 个 Button 控件和 1 个 TextBox 控件。
为这些控件设置属性,如下所示:
控件 名称 文本
Label1 lblFactorial1 (空白)
Label2 lblFactorial2 (空白)
Label3 lblAddTwo (空白)
Label4 lblRunLoops (空白)
Label5 lblTotalCalculations (空白)
Button1 btnFactorial1 Factorial
Button2 btnFactorial2 Factorial - 1
Button3 btnAddTwo Add Two
Button4 btnRunLoops Run a Loop
Textbox1 txtValue (空白)

创建 Calculator 组件

从“项目”菜单中选择“添加组件”。
将组件命名为 Calculator。
向 Calculator 组件添加公共变量

为 Calculator 打开代码编辑器。
添加创建公共变量的语句,这些变量用于将值从 frmCalculations 传递给每个线程。
变量 varTotalCalculations 将保留该组件执行的计算总数的累计值,而其他变量将接收来自窗体的值。

public int varAddTwo;
public int varFact1;
public int varFact2;
public int varLoopValue;
public double varTotalCalculations = 0;
向 Calculator 组件添加方法和事件

为事件声明委托,组件将使用这些事件向窗体传递值。
注意 尽管您将声明 4 个事件,但由于其中的两个事件将具有相同的签名,因此只需要创建 3 个委托。
紧接着上一步输入的变量声明的下方,键入下列代码:

// This delegate will be invoked with two of your events.
public delegate void FactorialCompleteHandler(double Factorial, double TotalCalculations);
public delegate void AddTwoCompleteHandler(int Result, double TotalCalculations);
public delegate void LoopCompleteHandler(double TotalCalculations, int Counter);
声明组件将用来与应用程序进行通信的事件。为实现此目的,紧接着上一步输入的代码的下方,添加下列代码。
public event FactorialCompleteHandler FactorialComplete;
public event FactorialCompleteHandler FactorialMinusOneComplete;
public event AddTwoCompleteHandler AddTwoComplete;
public event LoopCompleteHandler LoopComplete;
紧接着上一步键入的代码的下方,键入下列代码:
// This method will calculate the value of a number minus 1 factorial
// (varFact2-1!).
public void FactorialMinusOne()
{
double varTotalAsOfNow = 0;
double varResult = 1;
// Performs a factorial calculation on varFact2 - 1.
for (int varX = 1; varX <= varFact2 - 1; varX++)
{
varResult *= varX;
// Increments varTotalCalculations and keeps track of the current
// total as of this instant.
varTotalCalculations += 1;
varTotalAsOfNow = varTotalCalculations;
}
// Signals that the method has completed, and communicates the
// result and a value of total calculations performed up to this
// point.
FactorialMinusOneComplete(varResult, varTotalAsOfNow);
}

// This method will calculate the value of a number factorial.
// (varFact1!)
public void Factorial()
{
double varResult = 1;
double varTotalAsOfNow = 0;
for (int varX = 1; varX <= varFact1; varX++)
{
varResult *= varX;
varTotalCalculations += 1;
varTotalAsOfNow = varTotalCalculations;
}
FactorialComplete(varResult, varTotalAsOfNow);
}

// This method will add two to a number (varAddTwo+2).
public void AddTwo()
{
double varTotalAsOfNow = 0;
int varResult = varAddTwo + 2;
varTotalCalculations += 1;
varTotalAsOfNow = varTotalCalculations;
AddTwoComplete(varResult, varTotalAsOfNow);
}

// This method will run a loop with a nested loop varLoopValue times.
public void RunALoop()
{
int varX;
double varTotalAsOfNow = 0;
for (varX = 1; varX <= varLoopValue; varX++)
{
// This nested loop is added solely for the purpose of slowing down
// the program and creating a processor-intensive application.
for (int varY = 1; varY <= 500; varY++)
{
varTotalCalculations += 1;
varTotalAsOfNow = varTotalCalculations;
}
}
LoopComplete(varTotalAsOfNow, varLoopValue);
}
将用户输入传输到组件
下一步是向 frmCalculations 添加代码,以接收用户输入,以及从 Calculator 组件接收值和向它传输值。

实现 frmCalculations 的前端功能

在代码编辑器中打开 frmCalculations。
找到 public class frmCalculations 语句。紧接着 { 的下方键入:
Calculator Calculator1;
找到构造函数。紧接着 } 之前,添加以下行:
// Creates a new instance of Calculator.
Calculator1 = new Calculator();
在设计器中单击每个按钮,为每个控件的单击事件处理程序生成代码大纲,并添加代码以创建这些处理程序。
完成后,单击事件处理程序应该类似于以下形式:

private void btnFactorial1_Click(object sender, System.EventArgs e)
// Passes the value typed in the txtValue to Calculator.varFact1.
{
Calculator1.varFact1 = int.Parse(txtValue.Text);
// Disables the btnFactorial1 until this calculation is complete.
btnFactorial1.Enabled = false;
Calculator1.Factorial();
}

private void btnFactorial2_Click(object sender, System.EventArgs e)
{
Calculator1.varFact2 = int.Parse(txtValue.Text);
btnFactorial2.Enabled = false;
Calculator1.FactorialMinusOne();
}
private void btnAddTwo_Click(object sender, System.EventArgs e)
{
Calculator1.varAddTwo = int.Parse(txtValue.Text);
btnAddTwo.Enabled = false;
Calculator1.AddTwo();
}
private void btnRunLoops_Click(object sender, System.EventArgs e)
{
Calculator1.varLoopValue = int.Parse(txtValue.Text);
btnRunLoops.Enabled = false;
// Lets the user know that a loop is running
lblRunLoops.Text = "Looping";
Calculator1.RunALoop();
}
在上一步添加的代码的下方,键入以下代码以处理窗体将从 Calculator1 接收的事件:
protected void FactorialHandler(double Value, double Calculations)
// Displays the returned value in the appropriate label.
{
lblFactorial1.Text = Value.ToString();
// Re-enables the button so it can be used again.
btnFactorial1.Enabled = true;
// Updates the label that displays the total calculations performed
lblTotalCalculations.Text = "TotalCalculations are " +
Calculations.ToString();
}

protected void FactorialMinusHandler(double Value, double Calculations)
{
lblFactorial2.Text = Value.ToString();
btnFactorial2.Enabled = true;
lblTotalCalculations.Text = "TotalCalculations are " +
Calculations.ToString();
}

protected void AddTwoHandler(int Value, double Calculations)
{
lblAddTwo.Text = Value.ToString();
btnAddTwo.Enabled = true;
lblTotalCalculations.Text = "TotalCalculations are " +
Calculations.ToString();
}

protected void LoopDoneHandler(double Calculations, int Count)
{
btnRunLoops.Enabled = true;
lblRunLoops.Text = Count.ToString();
lblTotalCalculations.Text = "TotalCalculations are " +
Calculations.ToString();
}
在 frmCalculations 的构造函数中,紧挨在 } 之前添加下列代码,以处理窗体将从 Calculator1 接收的自定义事件:
Calculator1.FactorialComplete += new
Calculator.FactorialCompleteHandler(this.FactorialHandler);
Calculator1.FactorialMinusOneComplete += new
Calculator.FactorialCompleteHandler(this.FactorialMinusHandler);
Calculator1.AddTwoComplete += new
Calculator.AddTwoCompleteHandler(this.AddTwoHandler);
Calculator1.LoopComplete += new
Calculator.LoopCompleteHandler(this.LoopDoneHandler);
测试应用程序
现在项目已经创建完毕,该项目将能够执行若干个复杂计算的组件与窗体结合在一起。尽管尚未实现多线程处理功能,但在继续之前应该对项目进行测试,以验证它的功能。

测试项目

从“调试”菜单中选择“启动”。
应用程序启动并显示 frmCalculations。

在文本框中键入 4,然后单击标记为“添加两个”的按钮。
在按钮下方的标签中应该显示数字“6”,在 lblTotalCalculations 中应该显示“Total Calculations are 1”。

现在单击标记为“阶乘 - 1”的按钮。
该按钮的下方应显示数字“6”,而 lblTotalCalculations 中现在应显示“Total Calculations are 4”。

将文本框中的值更改为 20,然后单击标记为“阶乘”的按钮。
该按钮的下方显示数字“2.43290200817664E+18”,而 lblTotalCalculations 中现在显示为“Total Calculations are 24”。

将文本框中的值更改为 50000,然后单击标记为“运行循环”的按钮。
注意,在此按钮重新启用前有一个短暂然而明显的间隔。此按钮下的标签应显示“50000”,而总的计算次数显示为“25000024”。

将文本框中的值更改为 5000000 并单击标记为“运行循环”的按钮,紧接着单击标记为“添加两个”的按钮。再次单击它。
直到循环已经完成,该按钮以及窗体上的任何控件才有响应。

如果程序只运行单个执行线程,则类似上述示例的频繁使用处理器的计算倾向于占用该程序,直到计算已经完成。在下一节中,您将向应用程序添加多线程处理功能,以便一次可以运行多个线程。

添加多线程处理功能
上面的示例演示了只运行单个执行线程的应用程序的限制。在下一节,您将使用 Thread 类对象向组件添加多个执行线程。

添加 Threads 子例程

在代码编辑器中打开 Calculator.cs。
在代码顶部附近,找到类声明,紧接着 { 的下方,键入下列代码:
// Declares the variables you will use to hold your thread objects.
public System.Threading.Thread FactorialThread;
public System.Threading.Thread FactorialMinusOneThread;
public System.Threading.Thread AddTwoThread;
public System.Threading.Thread LoopThread;
在代码底部紧接着类声明结尾之前,添加以下方法:
public void ChooseThreads(int threadNumber)
{
// Determines which thread to start based on the value it receives.
switch(threadNumber)
{
case 1:
// Sets the thread using the AddressOf the subroutine where
// the thread will start.
FactorialThread = new System.Threading.Thread(new
System.Threading.ThreadStart(this.Factorial));
// Starts the thread.
FactorialThread.Start();
break;
case 2:
FactorialMinusOneThread = new
System.Threading.Thread(new
System.Threading.ThreadStart(this.FactorialMinusOne));
FactorialMinusOneThread.Start();
break;
case 3:
AddTwoThread = new System.Threading.Thread(new
System.Threading.ThreadStart(this.AddTwo));
AddTwoThread.Start();
break;
case 4:
LoopThread = new System.Threading.Thread(new
System.Threading.ThreadStart(this.RunALoop));
LoopThread.Start();
break;
}
}
当实例化 Thread 对象时,它要求一个 ThreadStart 对象形式的参数。ThreadStart 对象是一个指向开始线程的方法的地址的委托。ThreadStart 对象不能接受参数或者传递值,因此只能表示 void 方法。刚才实现的 ChooseThreads 方法将从调用它的程序接收一个值,并使用该值来确定要启动的适当线程。

向 frmCalculations 添加适当的代码

在代码编辑器中打开 frmCalculations.cs 文件,然后找到 protected void btnFactorial1_Click。
注释掉直接调用 Calculator1.Factorial1 方法的行,如下所示:
// Calculator1.Factorial()
添加下列行,以调用 Calculator1.ChooseThreads 方法:
// Passes the value 1 to Calculator1, thus directing it to start the
// correct thread.
Calculator1.ChooseThreads(1);
对其他 button_click 子例程作类似的修改。
注意 一定要为 Threads 参数包含适当的值。
完成后,代码看起来应该类似以下形式:

protected void btnFactorial1_Click(object sender, System.EventArgs e)
// Passes the value typed in the txtValue to Calculator.varFact1
{
Calculator1.varFact1 = int.Parse(txtValue.Text);
// Disables the btnFactorial1 until this calculation is complete
btnFactorial1.Enabled = false;
// Calculator1.Factorial();
Calculator1.ChooseThreads(1);
}

protected void btnFactorial2_Click(object sender, System.EventArgs e)
{
Calculator1.varFact2 = int.Parse(txtValue.Text);
btnFactorial2.Enabled = false;
// Calculator1.FactorialMinusOne();
Calculator1.ChooseThreads(2);
}
protected void btnAddTwo_Click(object sender, System.EventArgs e)
{
Calculator1.varAddTwo = int.Parse(txtValue.Text);
btnAddTwo.Enabled = false;
// Calculator1.AddTwo();
Calculator1.ChooseThreads(3);
}

protected void btnRunLoops_Click(object sender, System.EventArgs e)
{
Calculator1.varLoopValue = int.Parse(txtValue.Text);
btnRunLoops.Enabled = false;
// Lets the user know that a loop is running
lblRunLoops.Text = "Looping";
// Calculator1.RunALoop();
Calculator1.ChooseThreads(4);
}
封送处理对控件的调用
现在将加速窗体上的显示更新。鉴于控件总是由主执行线程所有,从属线程中对控件的任何调用都需要“封送处理”调用。封送处理是跨线程边界移动调用的行为,需要耗费大量的资源。为了使需要发生的封送处理量减到最少,并确保以线程安全方式处理调用,应使用 Control.BeginInvoke 方法来调用主执行线程上的方法,从而使必须发生的跨线程边界的封送处理量减到最少。当调用操作控件的方法时,这种调用非常必要。有关详细信息,请参见从线程操作控件。

创建控件调用过程

为 frmCalculations 打开代码编辑器。在声明部分,添加下列代码:
public delegate void FHandler(double Value, double Calculations);
public delegate void A2Handler(int Value, double Calculations);
public delegate void LDHandler(double Calculations, int Count);
Invoke 和 BeginInvoke 需要将适当方法的委托作为参数。这些代码行声明一些委托签名,这些签名将被 BeginInvoke 用于调用适当的方法。

在代码中添加下列空方法。
public void FactHandler(double Value, double Calculations)
{
}
public void Fact1Handler(double Value, double Calculations)
{
}
public void Add2Handler(int Value, double Calculations)
{
}
public void LDoneHandler(double Calculations, int Count)
{
}
在“编辑”菜单中,使用“剪切”和“粘贴”,从 FactorialHandler 方法中剪切所有代码,并将其粘贴到 FactHandler 中。
对 FactorialMinusHandler 和 Fact1Handler、AddTwoHandler 和 Add2Handler 以及 LoopDoneHandler 和 LDoneHandler 重复上面的步骤。
完成后,在 FactorialHandler、Factorial1Handler、AddTwoHandler 和 LoopDoneHandler 中应该没有剩余代码,并且它们曾经包含的所有代码应该已经移动到适当的新方法中。

调用 BeginInvoke 方法以异步调用这些方法。可以从窗体 (this) 或者窗体上的任何控件调用 BeginInvoke。
完成后,代码看起来应该类似以下形式:

protected void FactorialHandler(double Value, double Calculations)
{
// BeginInvoke causes asynchronous execution to begin at the address
// specified by the delegate. Simply put, it transfers execution of
// this method back to the main thread. Any parameters required by
// the method contained at the delegate are wrapped in an object and
// passed.
this.BeginInvoke(new FHandler(FactHandler), new Object[]
{Value, Calculations});
}
protected void FactorialMinusHandler(double Value, double Calculations)
{
this.BeginInvoke(new FHandler(Fact1Handler), new Object []
{Value, Calculations});
}

protected void AddTwoHandler(int Value, double Calculations)
{
this.BeginInvoke(new A2Handler(Add2Handler), new Object[]
{Value, Calculations});
}

protected void LoopDoneHandler(double Calculations, int Count)
{
this.BeginInvoke(new LDHandler(LDoneHandler), new Object[]
{Calculations, Count});
}
看起来似乎事件处理程序仅仅是对下一个方法进行调用。实际上,该事件处理程序实现了在主操作线程上调用方法。这种方法可节省跨线程边界的调用,并使多线程应用程序能够有效运行而不必担心导致死锁。有关在多线程环境下使用控件的详细信息,请参见从线程操作控件。

保存您的工作。
从“调试”菜单中选择“启动”,测试该解决方案。
在文本框内键入 10000000 并单击“运行循环”。
此按钮下方的标签中显示“Looping”。运行这个循环应该占用很长时间。如果它完成得太快,请相应地调整该数字的大小。

连续地快速单击仍在启用的三个按钮。您会发现所有按钮都响应您的输入。在“Add Two”下方的标签应该第一个显示结果。结果稍后将显示在阶乘按钮下方的标签中。估计这些结果会无限大,因为 10,000,000 的阶乘返回的数字对于双精度变量而言太大,以至超出了它包含的范围。最后,再过片刻,结果将返回到“运行循环”按钮下方。
正如刚刚观察到的,在四个单独的线程上同时执行四组独立的计算。用户界面保持对输入的响应,并在每个线程完成后返回结果。

协调线程
有经验的多线程应用程序用户可能会发现已键入的代码中存在细微缺陷。从 Calculator.cs 中每个执行计算的子例程中撤回以下代码行:

varTotalCalculations += 1;
varTotalAsOfNow = varTotalCalculations;
这两行代码递增公共变量 varTotalCalculations 并将局部变量 varTotalAsOfNow 设为此值。然后,该值被返回给 frmCalculations,并显示在标签控件中。但返回的值正确吗?如果只有单个执行线程在运行,则答案明显是正确的。但是如果有多个线程在运行,答案则变得不太确定。每个线程都具有递增变量 varTotalCalculations 的能力。有可能出现这样的情况:在一个线程递增该变量之后,但在它将该值复制到 varTotalAsOfNow 之前,另一个线程可能通过递增该变量而更改它的值。这将导致有可能每个线程实际上在报告不正确的结果。Visual C# 提供 lock 语句语句以允许线程的同步,从而确保每个线程始终返回准确的结果。lock 的语法如下所示:

lock(AnObject)
{
// Insert code that affects the object.
// Insert more code that affects the object.
// Insert more code that affects the object.
// Release the lock.
}
输入 lock 块后,在指定的线程对所讨论的对象拥有专用锁之前,对指定表达式的执行一直被堵塞。在上面显示的示例中,对 AnObject 的执行处于锁定状态。必须对返回引用的对象(而非返回值的对象)使用 lock。然后,执行以块的形式继续进行,而不会受到其他线程的干扰。作为一个单元执行的语句集称为“原子”。当遇到 } 时,表达式将被释放,线程可继续正常工作。

将 lock 语句添加到应用程序

在代码编辑器中打开 Calculator.cs。
找到下列代码的每个实例:
varTotalCalculations += 1;
varTotalAsOfNow = varTotalCalculations;
应该有此代码的四个实例,每个计算方法中有一个。

修改此代码,使其显示为如下形式:
lock(this)
{
varTotalCalculations += 1;
varTotalAsOfNow = varTotalCalculations;
}
保存工作,并按上例所示进行测试。
您可能注意到对程序性能的细微影响。这是因为当组件获得排他锁后,线程的执行停止。尽管它保证了正确性,但这种方法抵消了多线程带来的某些性能优点。应该认真考虑锁定线程的必要性,并且仅当绝对必要时才予以实现。

时间: 2024-09-28 12:08:57

利用 Visual C# 创作简单的多线程组件(转载于MSDN)的相关文章

在Visual J++中编写ASP COM组件

visual Java是一种以网络为中心的编程语言,许多只使用ASP脚本难以完成的任务可以用Java轻松地实现.同时,扩展ASP应用最好的方法莫过于加入COM组件.那么,可以利用Java为ASP开发组件吗?本文通过实例,说明了在Visual J++环境下开发COM组件的具体过程. 一.概述 自Java问世以来,各种开发工具.开发环境不断出现.这些环境和工具面向不同层次的用户,具有各自的优点.那么,使用Visual J++作为Java开发平台又有哪些优点呢?粗略地讲,这些优点包括: 熟悉的开发环境

利用Visual C#开发一个媒体播放器

visual|媒体 摘要:了解如何在 Microsoft Visual C# .NET 中使用 DirectShow 控件,如何开发一个媒体播放器.按照本文介绍的操作步骤,您可以创建一个简单 Visual C# 应用程序,用来播放数字音频和视频. 简介 Microsoft Visual C# 是世界上最流行的编程语言,利用 Visual C# 的最新版本 Visual C# .NET,您能够快速.有效地开发基于 Windows 窗体的应用程序,还可以为嵌入了 Microsoft Windows

在Visual J++中编写ASP COM组件(转)

visual Java是一种以网络为中心的编程语言,许多只使用ASP脚本难以完成的任务可以用Java轻松地实现.同时,扩展ASP应用最好的方法莫过于加入COM组件.那么,可以利用Java为ASP开发组件吗?本文通过实例,说明了在Visual J++环境下开发COM组件的具体过程. 一.概述 自Java问世以来,各种开发工具.开发环境不断出现.这些环境和工具面向不同层次的用户,具有各自的优点.那么,使用Visual J++作为Java开发平台又有哪些优点呢?粗略地讲,这些优点包括: 熟悉的开发环境

Visual C#创建和使用ActiveX组件

active|activex|visual|创建 开发基于.Net平台上的程序员是很难从本质上把Visual C#和ActiveX组件联起来,虽然在使用Visual C#开发应用程序时,有时为了快速开发或者由于.Net FrameWork SDK的不完整,还需要借助ActiveX.但即使如此,也很难把二者联系起来.其中的原因就是能够被Visual C#直接使用文件和通过Visual C#生成的可执行程序只可能是托管的文件.而Active X组件却都是非托管文件.这种文件的差异决定了二者本质"对立

利用Visual C#实现任务栏通知窗口

visual 想必大部分网友都使用过QQ.MSN等聊天程序,它们的界面都相当华丽,尤其是当网友上线以及消息提示时会有一个浮动的窗体从屏幕的右下方缓慢升起,既美观又人性化,作为程序员在享受的同时我们也不禁要问:这到底是怎么实现的呢?本文就利用Visual Studio .Net C# 2005以及.Net框架绘图技术来实现这种任务栏通知窗口. 简介 QQ和MSN的任务栏通知窗口很人性化,它可以在不丢失主窗体焦点的前提下显示一个具备皮肤Skin的通知窗体,当它显示一段时间后会自动消失,所以用户根本不

如何利用 Visual Studio 自带工具提高开发效率

原文:如何利用 Visual Studio 自带工具提高开发效率 Visual Stuido 是一款强大的Windows 平台集成开发工具,你是否好好地利用了它呢?   显示行号 有些时候(比如错误定位)的时候,显示行号将有利于我们进行快速定位.   如何显示 1. 工具 / 选项 / 文本编辑器 -> 选择对应的语言 2. 勾选 "行号"       使用书签 和平常意义的书签类似,当我们希望在日后某一时刻快速定位到一处代码时使用.比如在项目例会上,你需要演示本周你所做的一些改

一个简单的多线程即时通讯程序(类似QQ,MSN)

本文实现一个简单的多线程客户/服务器即时通讯应用程序,它将使用TCP连接.允许客户之间及客户 和服务器之间,个人消息与会议通信.最终目标是实现象雅虎/msn这样的即时通讯工具. [库] 我创建一个ChatLibrary,它包含命令及可以着色的消息.public enum Command { Login = 0, PersonalMessage = 1, ClientList = 2, Conference = 3, Logout = 4 }; public class Message { str

实现简单的多线程HTTP服务器

后期会丰富这个服务器,实现更多的功能,例如: 1.支持POST方式提交 2.支持二进制的流传送 3.支持线程池处理 4.采用NIO非阻塞形式实现 1package thread; 2 3import java.io.BufferedReader; 4import java.io.IOException; 5import java.io.InputStream; 6import java.io.InputStreamReader; 7import java.io.OutputStream; 8im

Linux下一个简单的多线程互斥锁的例子

本篇文章是对Linux下一个简单的多线程互斥锁的例子进行了分析介绍,需要的朋友可以参考下   复制代码 代码如下: #include <stdio.h> #include <pthread.h> pthread_mutex_t Device_mutex ; int count=0; void thread_func1() {    while(1)    {        pthread_mutex_lock(&Device_mutex);        printf(&q