(21)多线程实例应用:双色球(6红+1蓝)

一、需求

1.双色球: 投注号码由6个红色球号码和1个蓝色球号码组成。

2.红色球号码从01--33中选择,红色球不能重复。

3.蓝色球号码从01--16中选择。

4.最终结果7个号码 :6+1;即33选6(红)+ 16选1(蓝)

5.产品:

能用;用户放心使用;

原则:靠运气,不能有暗箱操作,号码开奖的随机性。

6.做法思路:

(1)从左往右---有序变化

(2)从右往左---有序变化

(3)同一时刻,球号码都变化~~

(4)可以做到让所有的球都变化,且都是相互独立的变化,随机性(推荐)

二、程序

1、界面: 6个红球label显示LblRedNum1-LblRedNum6,一个蓝球LblBlue。

两个Button,BtnStart与BtnStop。一个listBox1.

2、代码:

cs 复制代码
        private string[] redNums = Enumerable.Range(1, 33).Select(i => i.ToString("00")).ToArray();
        private string[] blueNums = Enumerable.Range(1, 16).Select(i => i.ToString("00")).ToArray();
        private object lockObj = new object();
        private List<Task> tasks = new List<Task>();
        private CancellationTokenSource cts;

        private async void BtnStart_Click(object sender, EventArgs e)
        {
            BtnStart.Enabled = false;
            BtnStop.Enabled = true;
            cts = new CancellationTokenSource();
            CancellationToken ct = cts.Token;

            //初始化,置00
            foreach (Label lbl in Controls.OfType<Label>().Where(b => b.Name.Contains("Red")))
            { lbl.Text = "00"; }

            //开7个线程
            foreach (Label lbl in Controls.OfType<Label>())
            {
                if (lbl.Name.Contains("Blue"))
                {
                    tasks.Add(Task.Run(async () =>//蓝球显示
                    {
                        while (!ct.IsCancellationRequested)
                        {
                            await Task.Delay(200);
                            string strBlue = blueNums[GetRandom(0, 16)];
                            lbl.Invoke(new Action(() =>
                            {
                                lbl.Text = strBlue;
                            }));
                        }
                    }));
                }
                else
                {
                    tasks.Add(Task.Run(async () =>//红球显示
                     {
                         while (!ct.IsCancellationRequested)
                         {
                             await Task.Delay(200);
                             int idx = GetRandom(0, 33);
                             string strRed = redNums[idx];
                             lock (lockObj)
                             {
                                 List<string> list = GetCurNumList();
                                 if (!list.Contains(strRed))
                                 {
                                     lbl.Invoke(new Action(() => { lbl.Text = strRed; }));
                                     redNums[idx] = strRed;
                                 }
                             }
                         }
                     }));
                }
            }

            await Task.Run(() =>//任务取消时显示
                 {
                     Task.WaitAll(tasks.ToArray());
                     Invoke(new Action(() =>
                     {
                         List<string> list = new List<string>();
                         foreach (Label lbl in this.Controls.OfType<Label>().Where(b => b.Name.Contains("Red")))
                         {
                             list.Add(lbl.Text);
                         }
                         list.Sort();
                         list.Add(LblBlue.Text);
                         listBox1.Items.Add(string.Join(",", list.ToArray()));
                     })
                     );
                 });
        }

        private List<string> GetCurNumList()//返回当前红球列表
        {
            List<string> list = new List<string>();
            foreach (Label lbl in this.Controls.OfType<Label>().Where(b => b.Name.Contains("Red")))
            { Invoke(new Action(() => { list.Add(lbl.Text); })); }

            return list;
        }

        private int GetRandom(int min, int max)//产生强随机数
        {
            byte[] bytes = new byte[4];
            using (var rng = RandomNumberGenerator.Create())
            { rng.GetBytes(bytes); }

            int seed = BitConverter.ToInt32(bytes, 0);
            return new Random(seed).Next(min, max);
        }

        private void BtnStop_Click(object sender, EventArgs e)
        {
            cts.Cancel();
            BtnStart.Enabled = true;
            BtnStop.Enabled = false;
        }

        private void Form1_Load(object sender, EventArgs e)
        { BtnStop.Enabled = false; }

三、细节

1、创建两个数组 ,根据随机产生的索引,从而得到随机的数。

比如,随机产生索引3,那么对于红球redNum[3]就是随机的产生的数

随机数用强随机数。根据自定义返回对应的字节。因为需要种子seed是int,所以需要4个字节即可,然后用BitConvert静态函数转换得取seed,从而产生较为真实的随机数。

2、蓝球用一个线程,红球用6个线程同时运行。

蓝球,不用管。

红球来自01-33不能重复,因此每次都得从6个红球中比较是否有相同的,相同则再次重新产生,直到得到6个不同的数为止。

6个线程一样这样操作,但容易竞争,比如都比较出与当前6个label数字不一样的,但这两个线程都产生的是相同的数字,比如是5,那么最后就会有重复的情况,为此设置互斥锁,产生数字时只准一个线程进去,改变当前label列表后,再退出,第二个线程再进去比较,得出不同后更新列表,再退出,如此循环,可使当前label的数字一直不同。

3、结果显示。

为了防止死锁,开一个子线程来等待前面7个线程的结束,并使用await防止假死。

另外,对6个红球排序后,把蓝球放在最末,加入listbox1显示。(不能全部排序,红蓝是两部分)

相关推荐
新手unity自用笔记11 小时前
项目-坦克大战学习-子弹的移动与销毁
笔记·学习·c#
qinzechen12 小时前
分享几个做题网站------学习网------工具网;
java·c语言·c++·python·c#
yufei-coder16 小时前
C# Windows 窗体开发基础
vscode·microsoft·c#·visual studio
dangoxiba16 小时前
[Unity Demo]从零开始制作空洞骑士Hollow Knight第十三集:制作小骑士的接触地刺复活机制以及完善地图的可交互对象
游戏·unity·visualstudio·c#·游戏引擎
AitTech16 小时前
深入理解C#中的TimeSpan结构体:创建、访问、计算与格式化
开发语言·数据库·c#
hiyo58520 小时前
C#中虚函数和抽象函数的概念
开发语言·c#
开心工作室_kaic1 天前
基于微信小程序的校园失物招领系统的设计与实现(论文+源码)_kaic
c语言·javascript·数据库·vue.js·c#·旅游·actionscript
时光追逐者1 天前
WaterCloud:一套基于.NET 8.0 + LayUI的快速开发框架,完全开源免费!
前端·microsoft·开源·c#·.net·layui·.netcore
friklogff1 天前
【C#生态园】打造现代化跨平台应用:深度解析.NET桌面应用工具
开发语言·c#·.net
hiyo5852 天前
C#的面向对象
开发语言·c#