详解C#中线程传参,返回值和多线程冲突问题的解决

在C#中,开启一个线程很容易。

Thread Th1= new Thread(func);
Th1.Start();
 
private void func(object Obj)
{
 //处理代码
}

很多情况下,我们是需要对线程进行传递参数的,这个也简单。

1、线程的单一参数传递

private void button1_Click(object sender, EventArgs e)
 {
 Thread Th1= new Thread(func);
 Th1.Start("CSDN");
 Thread.Sleep(500);
 }
 
 private void func(object Obj)
 {
 string Str = Obj as string;
 textBox1.BeginInvoke(new Action(() =>
 {
 textBox1.Text = $"传入的参数:{Str}";
 }));
 }

2、线程的多参数传递以及返回值

上面的例子是单一的参数,参数要求是对象,使用的时候进行了拆箱,根据上面的例子对于多参数,可以使用中间对象来处理,就是在中间对象中放置参数和获取处理后的结果。

private void button1_Click(object sender, EventArgs e)
 {
 FinancialInfo FI=new FinancialInfo();
 FI.PersonName = "CSDN";
 FI.PersonDeposit = 123;
 Thread Th1 = new Thread(FI.ThreadChangeFinanceialInfo);
 Th1.Start();
 Thread.Sleep(500);
 textBox1.Text=FI.PersonName+Environment.NewLine+FI.PersonDeposit.ToString();
 }
 
 private class FinancialInfo
 {
 private string Name=string.Empty;
 private int Deposit=0;
 public string PersonName
 {
 get { return Name; }
 set { Name = value; }
 }
 
 public int PersonDeposit
 {
 get { return Deposit; }
 set { Deposit = value; }
 }
 
 public void ThreadChangeFinanceialInfo() 
 {
 this.Name = this.Name + " | C#";
 this.Deposit = this.Deposit + 100;
 }

3、多线程可能引起的冲突

多线程在处理同一对象时容易引起潜在的冲突,这个显而易见,例如:

private void button1_Click(object sender, EventArgs e)
 {
 FinancialInfo FI = new FinancialInfo();
 FI.PersonName = "CSDN";
 FI.PersonDeposit = 123;
 Thread Th1 = new Thread(FI.ThreadAdd);
 Thread Th2 = new Thread(FI.ThreadReduce);
 Th1.Start();
 Th2.Start();
 Thread.Sleep(5000);
 textBox1.Text = textBox1.Text + FI.PersonName +"|"+FI.PersonDeposit.ToString()+Environment.NewLine;
 }
 
 private class FinancialInfo
 {
 private string Name=string.Empty;
 private int Deposit=0;
 public string PersonName
 {
 get { return Name; }
 set { Name = value; }
 }
 
 public int PersonDeposit
 {
 get { return Deposit; }
 set { Deposit = value; }
 }
 
 public void ThreadAdd()
 {
 for (int i = 0; i < 1000000; i++)
 {
 this.Deposit = this.Deposit + 1;
 }
 }
 
 public void ThreadReduce()
 {
 for (int i = 0; i < 1000000; i++)
 {
 this.Deposit = this.Deposit - 1;
 }
 }
 }

显示结果:

按道理, FI.PersonDeposit的值是123,加了1000000,也减了1000000,那么最终的结果应该还是123,为什么会是这样呢?

这就是多线程在处理同一对象时所产生的冲突了,产生的就是所谓的“脏数据”。

上面的代码因为等待线程执行完,进行了休眠,可以使用Task来写更简单。

var task1 = new Task(FI.ThreadAdd);
 var task2 = new Task(FI.ThreadReduce);
 task1.Start();
 task2.Start();
 
 Task.WaitAll(task1,task2);

Task是比Thread更加高级的概念,一个Task至少包含一个Thread。

解决上面的冲突就是对可能引起冲突的对象进行加锁判断。

完整代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Text;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace MultiThread
{
 public partial class Form3 : Form
 {
 
 private static readonly object LockObj=new object();
 
 public Form3()
 {
 InitializeComponent();
 }
 
 private void button1_Click(object sender, EventArgs e)
 {
 FinancialInfo FI = new FinancialInfo();
 FI.PersonName = "CSDN";
 FI.PersonDeposit = 123;
 var task1 = new Task(FI.ThreadAdd);
 var task2 = new Task(FI.ThreadReduce);
 task1.Start();
 task2.Start();
 Task.WaitAll(task1, task2);
 textBox1.Text = textBox1.Text + FI.PersonName +"|"+FI.PersonDeposit.ToString()+Environment.NewLine;
 }
 
 
 private class FinancialInfo
 {
 private string Name=string.Empty;
 private int Deposit=0;
 public string PersonName
 {
 get { return Name; }
 set { Name = value; }
 }
 
 public int PersonDeposit
 {
 get { return Deposit; }
 set { Deposit = value; }
 }
 
 public void ThreadChangeFinanceialInfo() 
 {
 this.Name = this.Name + " | C#";
 this.Deposit = this.Deposit + 100;
 }
 
 public void ThreadAdd()
 {
 for (int i = 0; i < 1000000; i++)
 {
 lock(LockObj)
 {
 this.Deposit = this.Deposit + 1;
 } 
 }
 }
 
 public void ThreadReduce()
 {
 for (int i = 0; i < 1000000; i++)
 {
 lock(LockObj)
 {
 this.Deposit = this.Deposit - 1;
 } 
 }
 }
 }
 }
}

显示结果:

上面显示出了正确的结果,但是会耗时。

作者:dawn原文地址:https://blog.csdn.net/dawn0718/article/details/128107337

%s 个评论

要回复文章请先登录注册