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

2023-12-21 06:15:24

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱: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代码的方式,判断注释前后运行结果有没有差异。

文章来源:https://blog.csdn.net/feixiaoxing/article/details/135111058
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。