C# 让程序代码在固定的线程里运行

news/2024/10/25 3:20:07/

一、概述

在平时我们的开发中,多线程也是经常用到的,尤其是我们做上位机行业的,平时更是必不可少,在以前我做 Unity3d 开发时,其实并不用关心线程的问题,在 Unity 的开发中,所有代码基本都是单线程运行,而且还可以保持比较高的运行速度,当然,这不是本次要讨论的话题。

有人可能会问我这么做的意义,系统自动分配线程不是更好么?当然好,只是有时候调用其他的一些框架,就避免不了需要锁定线程,比如,C# 调用 C++ 的 DLL,最近在做发那科的上位机程序,在调用 fanuc 的一些方法时,需要传入一个句柄,在测试中,我发现如果使用多线程,切换到了其他的线程根本无法行的通,返回数据都是报错,但是在主程序中,虽然可以正常运行,但是一但执行了写入G代码这类接口时,整个程序全部卡死,这就不得不用多线程,并且必须让指定的代码,在指定的程序中运行。

二、实现功能

新建一个 winform 项目,界面中就两个按钮,用来测试多线程的影响

新建一个类 MessagePump,当前类的功能就是开启一个线程,加入一个任务队列,并重复的检测在任务队列中有没有可以执行的任务。

其实当类还可以写的更复杂,比如,自定义一个任务系统,可以传入任务的名字,任务的委托,和回调的委托,任务需要的一些参数等,这里我就不具体去写啦,有需求的可以自己试试。

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;internal class MessagePump
{private static bool m_Working = false;private static Queue<Action> m_Actions = new Queue<Action>();public static void Start(){if (m_Working)return;m_Working = true;Thread t = new Thread(DoPump);t.Name = "Message Pump Thread";t.Start();}private static void DoPump(){while (m_Working){try{Monitor.Enter(m_Actions);while (m_Actions.Count > 0){Console.WriteLine("------start------");m_Actions.Dequeue()();Console.WriteLine("------end------");}}finally{Monitor.Exit(m_Actions);}Thread.Sleep(500);}}public static void Stop(){m_Working = false;}public static void AddMessage(Action act){Task.Run(() =>{lock (m_Actions){m_Actions.Enqueue(act);}});}
}

Form1 窗体的代码

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace 多线程
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){#region 注释//var c = new System.Collections.Concurrent.BlockingCollection<Tuple<bool, Action>>();//var t = new Thread(() =>//{//    while (true)//    {//        var item = c.Take();//        if (!item.Item1) break;//        item.Item2();//    }//    Console.WriteLine("Exiting thread");//});//t.Start();//Console.WriteLine("Press any key to queue first action");//Console.ReadKey();//c.Add(Tuple.Create<bool, Action>(true, () => Console.WriteLine("Executing first action")));//Console.WriteLine("Press any key to queue second action");//Console.ReadKey();//c.Add(Tuple.Create<bool, Action>(true, () => Console.WriteLine("Executing second action")));//Console.WriteLine("Press any key to stop the thread");//Console.ReadKey();//c.Add(Tuple.Create<bool, Action>(false, null));//Console.WriteLine("Press any key to exit");#endregionMessagePump.Start();MessagePump.AddMessage(() =>{string threadid = Thread.CurrentThread.ManagedThreadId.ToString();Console.WriteLine("-------------任务{0}当前的线程ID:{1}", 1, threadid);Thread.Sleep(1000);Console.WriteLine("-------------任务1完成-------------");});MessagePump.AddMessage(() =>{string threadid = Thread.CurrentThread.ManagedThreadId.ToString();Console.WriteLine("-------------任务{0}当前的线程ID:{1}", 1, threadid);int value = 0;while (true){Thread.Sleep(1000);value++;if (value > 10){break;}}Console.WriteLine("-------------任务2完成-------------");});MessagePump.AddMessage(() =>{string threadid = Thread.CurrentThread.ManagedThreadId.ToString();Console.WriteLine("-------------任务{0}当前的线程ID:{1}", 3, threadid);Thread.Sleep(3000);Console.WriteLine("-------------任务3完成-------------");});}private void Form1_FormClosing(object sender, FormClosingEventArgs e){MessagePump.Stop();}//使用异步打开定时器private void button1_Click(object sender, EventArgs e){isStop = true;DosomeThingAsync();}private static bool isStop = false;private static async void DosomeThingAsync(){while (isStop){await Task.Delay(TimeSpan.FromSeconds(2));string threadid = Thread.CurrentThread.ManagedThreadId.ToString();Console.WriteLine("定时器--线程ID:" + threadid);}}//新添加一个任务private void button2_Click(object sender, EventArgs e){MessagePump.AddMessage(() =>{string threadid = Thread.CurrentThread.ManagedThreadId.ToString();Console.WriteLine("-------------任务{0}当前的线程ID:{1}", 5, threadid);Thread.Sleep(5000);Console.WriteLine("-------------任务{0}完成-------------", 5);});}}
}

窗体在运行后,会自动添加任务,并执行,还任务还没执行完成时,我们点击 “使用异步打开定时器” 这个按钮,临时切换一些线程,看看之前添加的线程会不会改变线程ID

点击 “新添加一个任务” 按钮,可以看到,线程的ID并没有变,这样,我们锁定线程去执行代码的功能就实现了。

所有的代码都在这里了,源码我就不上传了。 

三、SynchronizationContext

提供在各种同步模型中传播同步上下文的基本功能。

类 SynchronizationContext 是提供不同步的自由线程上下文的基类。

此类实现的同步模型的目的是允许公共语言运行时的内部异步/同步操作在不同的同步模型中正常运行。 此模型还简化了托管应用程序为了在不同的同步环境中正常工作而必须遵循的一些要求。

同步模型的提供程序可以扩展此类,并为这些方法提供自己的实现。

上面是微软的一些解释,推荐帖子:

同步上下文(SynchronizationContext) 和 C#中跨线程更新UI的方法总结_c# synchronizationcontext_kalvin_y_liu的博客-CSDN博客

c#:深入理解SynchronizationContext_c# synchronizationcontext_jackletter的博客-CSDN博客

SynchronizationContext类的方法原型如下:

namespace System.Threading
{//// 摘要://     提供在各种同步模型中传播同步上下文的基本功能。public class SynchronizationContext{//// 摘要://     创建 System.Threading.SynchronizationContext 类的新实例。public SynchronizationContext();//// 摘要://     获取当前线程的同步上下文。//// 返回结果://     一个 System.Threading.SynchronizationContext 对象,它表示当前同步上下文。public static SynchronizationContext Current { get; }//// 摘要://     设置当前同步上下文。//// 参数://   syncContext://     要设置的 System.Threading.SynchronizationContext 对象。[SecurityCritical][TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]public static void SetSynchronizationContext(SynchronizationContext syncContext);//// 摘要://     用于等待指定数组中的任一元素或所有元素接收信号的 Helper 函数。//// 参数://   waitHandles://     一个类型为 System.IntPtr 的数组,其中包含本机操作系统句柄。////   waitAll://     若等待所有句柄,则为 true;若等待任一句柄,则为 false。////   millisecondsTimeout://     等待的毫秒数,或为 System.Threading.Timeout.Infinite (-1),表示无限期等待。//// 返回结果://     满足等待的对象的数组索引。[CLSCompliant(false)][PrePrepareMethod][ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)][SecurityCritical]protected static int WaitHelper(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout);//// 摘要://     当在派生类中重写时,创建同步上下文的一个副本。//// 返回结果://     一个新的 System.Threading.SynchronizationContext 对象。public virtual SynchronizationContext CreateCopy();//// 摘要://     确定是否需要等待通知。//// 返回结果://     如果需要等待通知,则为 true;否则为 false。public bool IsWaitNotificationRequired();//// 摘要://     当在派生类中重写时,响应操作已完成的通知。public virtual void OperationCompleted();//// 摘要://     当在派生类中重写时,响应操作已开始的通知。public virtual void OperationStarted();//// 摘要://     当在派生类中重写时,将异步消息调度到一个同步上下文。//// 参数://   d://     要调用的 System.Threading.SendOrPostCallback 委托。////   state://     传递给委托的对象。public virtual void Post(SendOrPostCallback d, object state);//// 摘要://     当在派生类中重写时,将一个同步消息调度到一个同步上下文。//// 参数://   d://     要调用的 System.Threading.SendOrPostCallback 委托。////   state://     传递给委托的对象。//// 异常://   T:System.NotSupportedException://     在 Windows Store 应用程序中调用的方法。用于 Windows Store 应用程序的 System.Threading.SynchronizationContext//     的实现应用不支持 System.Threading.SynchronizationContext.Send(System.Threading.SendOrPostCallback,System.Object)//     方法。public virtual void Send(SendOrPostCallback d, object state);//// 摘要://     等待指定数组中的任一元素或所有元素接收信号。//// 参数://   waitHandles://     一个类型为 System.IntPtr 的数组,其中包含本机操作系统句柄。////   waitAll://     若等待所有句柄,则为 true;若等待任一句柄,则为 false。////   millisecondsTimeout://     等待的毫秒数,或为 System.Threading.Timeout.Infinite (-1),表示无限期等待。//// 返回结果://     满足等待的对象的数组索引。//// 异常://   T:System.ArgumentNullException://     waitHandles 为 null。[CLSCompliant(false)][PrePrepareMethod][SecurityCritical]public virtual int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout);//// 摘要://     设置指示需要等待通知的通知,并准备回调方法以使其在发生等待时可以更可靠地被调用。[SecuritySafeCritical]protected void SetWaitNotificationRequired();}
}

使用 SynchronizationContext 也可以实现切换线程执行的效果,只是平时这种方式在我们工作中用的并不是很多,具体案例就不做介绍了。

如果当前的文章对你有所帮助,欢迎点赞 + 留言,有疑问也可以私信,谢谢。

end


http://www.ppmy.cn/news/315309.html

相关文章

建筑概论丨三、民用建筑构造

5屋顶 屋顶的类型 屋面的常用坡度和坡度范围 屋顶的防水等级 平屋顶 平屋顶的防水 坡屋顶 组成 承重结构 屋面盖料 檐口构造 含两类 1挑檐口 2女儿墙檐口

winrar解压的文件在哪里?

有时候我们在解压临时文件的时候&#xff0c;没有注意到解压到哪里去了&#xff0c;解压完了就找不到文件&#xff0c;这该怎么办&#xff1f; 最简单的方法是再重新压缩一遍文件&#xff0c;但是这种操作会导致我们电脑容量在不知不觉间被占用了。 大家最好还是找到解压文件…

波士顿房价估计

一、导入模块 import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns plt.rcParams[font.sans-serif] [SimHei]二、载入数据 from sklearn import datasets # 加载波士顿房价的数据集 boston datasets.load_boston()print(boston…

伦敦备受青睐的标志性建筑——皇家阿尔伯特音乐厅

说到伦敦重要的演出场所&#xff0c;当然不能不提皇家阿尔伯特音乐厅&#xff08;Royal Albert Hall&#xff09;。披头士乐队、滚石乐队、阿黛尔、萨顶顶、谭晶、郎朗等著名歌手和音乐人都曾在这里举办演唱会或音乐会&#xff0c;一年一度的逍遥音乐节更是让这座音乐厅备受瞩目…

芬兰雅威联手金茂府 打响“城市空气革命”第一仗

随着中国经济飞速发展&#xff0c;中国高端豪宅地产项目也越来越多&#xff0c;房地产业内人士直言&#xff1a;“高端城市豪宅必须把好空气质量这一关&#xff0c;否则就难以获得高端群体的认同。”不得不说&#xff0c;人们对呼吸健康的重视继雾霾之后&#xff0c;在经历过此…

波士顿房价预测(一)

波士顿房价预测(一) 导语&#xff1a; 开始学习机器学习相关知识。波士顿房价预测&#xff0c;也是很经典的一个案例&#xff0c;我会陆续把自己完成整个项目的过程记录下来&#xff0c;还有就是可能会出现一定的差错&#xff0c;或者数据分析库使用的不是很熟练的情况&#xf…

波斯顿房价 (1)

#房价预测 import torch #data import numpy as np import re ff open(r"C:\Users\22383\Desktop\备份pytorch\000、课程配套资料\Pytorch_code-master\pytorch_code\04\cls_reg\housing.data").readlines() data [] for item in ff:out re.sub(r"\s{2,}&quo…

波士顿房价预测

波士顿房价预测 在这节课中&#xff0c;我们使用波士顿房价数据集来实现一个更加完整的例子&#xff0c;关于波士顿房价数据集&#xff0c;我们在第6讲中进行了详细的介绍&#xff0c;这是对它可视化的结果 其中的每一个子图是数据集中的一个属性&#xff0c;和房价之间的关系…