如何让两个不同的线程同时写入一个变量?C#

如何让两个不同的线程同时写入一个变量?C#,c#,multithreading,C#,Multithreading,我正在尝试建立一个ATM,我需要展示一个数据竞赛的例子 为此,我需要两个线程同时写入一个变量(我想) 当点击“取出10$”按钮时,线程会写入这个变量,但我不能同时点击两个按钮,这意味着我不能真正显示数据。下面是按钮单击事件的代码 private void button1_Click(object sender, EventArgs e) { if (Form1.currAcc.getBalance() < 10) { System.Windows.Forms.Message

我正在尝试建立一个ATM,我需要展示一个数据竞赛的例子

为此,我需要两个线程同时写入一个变量(我想)

当点击“取出10$”按钮时,线程会写入这个变量,但我不能同时点击两个按钮,这意味着我不能真正显示数据。下面是按钮单击事件的代码

private void button1_Click(object sender, EventArgs e)
{
  if (Form1.currAcc.getBalance() < 10)
  {
    System.Windows.Forms.MessageBox.Show("Insuficient Funds");
    this.Close();
  }
  else
  {
    Form1.currAcc.setBalance(Form1.currAcc.getBalance() - 10);
    System.Windows.Forms.MessageBox.Show("Succesfully withdrawn 10$");
    this.Close();
  }
}
private void按钮1\u单击(对象发送者,事件参数e)
{
if(Form1.currAcc.getBalance()<10)
{
System.Windows.Forms.MessageBox.Show(“资金不足”);
这个。关闭();
}
其他的
{
Form1.currAcc.setBalance(Form1.currAcc.getBalance()-10);
System.Windows.Forms.MessageBox.Show(“成功提取10美元”);
这个。关闭();
}
}
编辑:这给了我一场数据竞赛:

        private void button1_Click(object sender, EventArgs e)
    {
        if (Form1.currAcc.getBalance() < 10)
        {
            System.Windows.Forms.MessageBox.Show("Insuficient Funds");
            this.Close();
        }
        else
        {
            currentBalance = Form1.currAcc.getBalance();
            Form5.timerStatus++;

            if (Form5.timerStatus == 1)
            {
                Thread.Sleep(3000);
                Form1.currAcc.setBalance(currentBalance - 10);
                System.Windows.Forms.MessageBox.Show("Succesfully withdrawn 10$");
            }

            else{
                Form1.currAcc.setBalance(currentBalance - 10);
                System.Windows.Forms.MessageBox.Show("Succesfully withdrawn 10$");
                Form5.timerStatus = 0;
            }
            this.Close();
        }
    }
private void按钮1\u单击(对象发送者,事件参数e)
{
if(Form1.currAcc.getBalance()<10)
{
System.Windows.Forms.MessageBox.Show(“资金不足”);
这个。关闭();
}
其他的
{
currentBalance=Form1.currencc.getBalance();
Form5.timerStatus++;
如果(Form5.timerStatus==1)
{
睡眠(3000);
表1.当前余额(当前余额-10);
System.Windows.Forms.MessageBox.Show(“成功提取10美元”);
}
否则{
表1.当前余额(当前余额-10);
System.Windows.Forms.MessageBox.Show(“成功提取10美元”);
Form5.timerStatus=0;
}
这个。关闭();
}
}
这相当简单:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        static void Main()
        {
            for (int i = 0; i < 4; ++i)
                Task.Run(() => withdraw(800m));

            Thread.Sleep(1000);

            // Balance should be 200 unless a race condition occured.
            Console.WriteLine(balance);
        }

        static void withdraw(decimal amount)
        {
            if (balance >= amount)
                balance -= amount;
        }

        static decimal balance = 1000.0m;
    }
}
这相当容易:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        static void Main()
        {
            for (int i = 0; i < 4; ++i)
                Task.Run(() => withdraw(800m));

            Thread.Sleep(1000);

            // Balance should be 200 unless a race condition occured.
            Console.WriteLine(balance);
        }

        static void withdraw(decimal amount)
        {
            if (balance >= amount)
                balance -= amount;
        }

        static decimal balance = 1000.0m;
    }
}

演示竞争条件的最简单方法是使用并行库,因为它将同时启动多个线程。下面的代码很好地演示了这一点

Parallel.For(1, 11, r =>
        {
            Console.WriteLine($"Thread{r}: Balance: ${_balance}");

            if (_balance < r)
            {
                Console.WriteLine($"Thread{r}: Insufficient funds ${_balance}");
                return;
            }

            _balance -= r;

            Console.WriteLine($"Thread{r}: Withdraw ${r}. New Balance is ${_balance}");
        });

        Console.WriteLine("Press any key to exit");
        Console.Read();
Parallel.For(1,11,r=>
{
WriteLine($“Thread{r}:Balance:${u Balance}”);
如果(_余额
它将生成这样的输出

线程1:余额:20美元
线程1:提取1美元。新余额为19美元
线程6:余额:$19
线程2:余额:20美元
线程3:余额:20美元
线程4:余额:20美元
线程5:余额:$19
线程8:余额:4美元
线程8:资金不足$4
线程9:余额:4美元
线程9:资金不足4美元
线程10:余额:4美元
线程10:资金不足$4
线程4:提取4美元。新余额为4美元
线程5:资金不足$4
线程6:提取6美元。新余额为13美元
线程2:提取2美元。新余额为11美元
线程7:余额:11美元
线程7:资金不足4美元
线程3:提取3美元。新余额为8美元
按任意键退出


这表明,螺纹最初看到的平衡和实际减去的平衡不一样,例如,线程5在启动时看到了$20,但当它试图提取$5时,它得到了资金不足的响应

证明竞争条件的最简单方法是使用并行库,因为它将同时启动多个线程。下面的代码很好地演示了这一点

Parallel.For(1, 11, r =>
        {
            Console.WriteLine($"Thread{r}: Balance: ${_balance}");

            if (_balance < r)
            {
                Console.WriteLine($"Thread{r}: Insufficient funds ${_balance}");
                return;
            }

            _balance -= r;

            Console.WriteLine($"Thread{r}: Withdraw ${r}. New Balance is ${_balance}");
        });

        Console.WriteLine("Press any key to exit");
        Console.Read();
Parallel.For(1,11,r=>
{
WriteLine($“Thread{r}:Balance:${u Balance}”);
如果(_余额
它将生成这样的输出

线程1:余额:20美元
线程1:提取1美元。新余额为19美元
线程6:余额:$19
线程2:余额:20美元
线程3:余额:20美元
线程4:余额:20美元
线程5:余额:$19
线程8:余额:4美元
线程8:资金不足$4
线程9:余额:4美元
线程9:资金不足4美元
线程10:余额:4美元
线程10:资金不足$4
线程4:提取4美元。新余额为4美元
线程5:资金不足$4
线程6:提取6美元。新余额为13美元
线程2:提取2美元。新余额为11美元
线程7:余额:11美元
线程7:资金不足4美元
线程3:提取3美元。新余额为8美元
按任意键退出

这表明线程最初看到的余额和实际减去的余额不一样,例如,线程5在开始时看到了20美元,但当它试图提取5美元时,得到了资金不足的响应,“代码”回答都是好的,但我认为有一个概念上的东西值得指出:多线程在同一时间点做某事并不重要

这些问题的本质是:由于缺少“同步”,当这些线程进行更新时无法预测。因此,根据最先进入的线程,最终会得到不同的结果

因此,让多个线程并行增加一个计数器已经足够了——如果以“非同步”的方式增加计数器,最终结果将(很可能)与预期值不匹配

意思:简单的事情,比如

fetch the current counter
do something else that takes a bit of time
write "counter+1" to counter
这已经足够好了。这些书写是否及时“接近”并不重要;唯一需要的是