C# WPF上位机开发(多线程中锁的使用)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

多线程编程一般都会涉及到锁的时候,很多人可能觉得很意外,为什么会需要这么一个锁。本质上,这主要还是因为多线程的执行中,本身一部分逻辑并不是原子操作导致的。有一个池塘喂鱼的例子最为经典。假设池塘有两个人同时去喂鱼,每一个人喂鱼之前,会先看一下池塘边上的牌子。假设牌子是红色的,代表已经喂过了;假设牌子是绿色的,则代表鱼还没有喂过。鱼本身只能吃一顿,如果连续喂的话,那么鱼可能会撑死。

现在就会出现这么一个情况,就是第一个人去喂鱼,但是他还没有来得及翻牌子的时候,第二个人来继续喂鱼。他一看鱼牌子是绿色的,还没有喂,那就就会选择继续投料。而他投料的同时,并不知道第一个人之前已经投喂过了。所以,这个时候,鱼就会被撑死了。

所以,为了解决这个问题,os一般会提供一个锁的机制,对于锁里面的操作,一定是不能打断的。只有所有操作都完成之后,才会释放自己的锁机制。为了解释锁是怎么使用的,以及说明如果不用锁的话,究竟有什么样的坏处,可以通过c# wpf编写一个demo进行说明下。

1、设置界面

界面还是只有一个按钮和一个textbox。按钮下去的时候,有两个thread同时递增1000万次,查看两个thread递增之后,总的数据次数是不是2000万。

复制代码
<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:local="clr-namespace:WpfApp"
        mc:Ignorable="d"
        Title="LockSimulationDemo" Height="480" Width="550">
    <Grid>
        <StackPanel>
            <Button x:Name="button"  Content="Start processing" Click="StartButton_Click" Height="40" Margin="5,40"/>
            <TextBox x:Name="Result" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Height="200" Margin="5"/>
        </StackPanel>
    </Grid>
</Window>

相关界面显示如下,

2、代码编写

代码编写主要就是按钮的回调函数。回调函数中,主要使用了Thread类、ThreadStart类这两个。线程注册函数是WorkerThreadMethod。创建好两个thread之后,就可以将他们start开始执行。

在线程注册函数中,会各循环1000万次。之所以会循环这么多次,是因为循环次数多了,才能看到锁的效果。没有锁的话,最终的累加次数不一定是2000万;反之,有了锁,肯定是2000万,这就是锁的用处所在。

复制代码
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Threading;

namespace WpfApp
{
    public partial class MainWindow : Window
    {
        private int total = 0;
        private readonly object _lockObject = new object(); // lock for synchronization

        // construct function
        public MainWindow()
        {
            InitializeComponent();
        }

        // button invoke function
        private void StartButton_Click(object sender, RoutedEventArgs e)
        {
            Thread newThread1 = new Thread(new ThreadStart(WorkerThreadMethod));
            Thread newThread2 = new Thread(new ThreadStart(WorkerThreadMethod));

            Result.Text = "";
            total = 0;
            button.IsEnabled = false;

            newThread1.Start();
            newThread2.Start();
        }

        // thread entry function
        private void WorkerThreadMethod()
        {
            for (int i = 0; i < 10000000; i++)
            {
                lock (_lockObject) // critical section
                {
                    total += 1;
                }
            }

            Application.Current.Dispatcher.Invoke(() =>
            {
                Result.AppendText(total.ToString() + "\n");
                button.IsEnabled = true;
            });
        }
    }
}

3、实验和验证

验证的话,编译没有啥问题,直接单击按钮即可。同时,这个按钮是可以连续单击,即一次结果出来之后可以反复测试的。中间测试的过程中,可以通过注释掉lock代码的方式,判断注释前后运行结果有没有差异。

相关推荐
mudtools14 小时前
.NET驾驭Word之力:理解Word对象模型核心 (Application, Document, Range)
c#·.net
侃侃_天下19 小时前
最终的信号类
开发语言·c++·算法
echoarts20 小时前
Rayon Rust中的数据并行库入门教程
开发语言·其他·算法·rust
Aomnitrix20 小时前
知识管理新范式——cpolar+Wiki.js打造企业级分布式知识库
开发语言·javascript·分布式
大飞pkz20 小时前
【设计模式】C#反射实现抽象工厂模式
设计模式·c#·抽象工厂模式·c#反射·c#反射实现抽象工厂模式
每天回答3个问题21 小时前
UE5C++编译遇到MSB3073
开发语言·c++·ue5
伍哥的传说21 小时前
Vite Plugin PWA – 零配置构建现代渐进式Web应用
开发语言·前端·javascript·web app·pwa·service worker·workbox
小莞尔21 小时前
【51单片机】【protues仿真】 基于51单片机八路抢答器系统
c语言·开发语言·单片机·嵌入式硬件·51单片机
我是菜鸟0713号1 天前
Qt 中 OPC UA 通讯实战
开发语言·qt
JCBP_1 天前
QT(4)
开发语言·汇编·c++·qt·算法