System.Timer.Timer的lock争用问题

__Meow __Meow 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区
好奇Win8的Loading动画,故尝试winform实现之。现在的问题是多个线程(Timer)共用一个Graphics对象(lock),出现了争用引起的错位问题,废话不多,上Code……

//辅助类
static class Common
{
//圆心
public static Point CenterPoint = new Point(25, 25);
//包围矩形
public static Rectangle Rect = new Rectangle(0, 0, 50, 50);

//绘图委托
public delegate void DrawDelegate();

//最慢速临界角度
public const int slowAngle_1 = 315;
public const int slowAngle_2 = 135;

//最快速临界角度
public const int quickAngle_1 = slowAngle_1 + 90 - 360;
public const int quickAngle_2 = slowAngle_2 + 90;

/// <summary>
/// 根据半径、角度求圆上坐标
/// </summary>
/// <param name="radius">半径</param>
/// <param name="angle">角度</param>
/// <returns>坐标</returns>
public static Point GetDotLocationByAngle(int radius, int angle)
{
int x, y;

x = (int)(CenterPoint.X + radius * Math.Cos(angle * Math.PI / 180));
y = (int)(CenterPoint.Y + radius * Math.Sin(angle * Math.PI / 180));

return new Point(x, y);
}
}


//窗体类
public partial class Form1 : Form
{
Dot[] dots = new Dot[5];

//当前活动点索引(用于辅助支持线程同步)
//public static int CurrentDotIndex = 0;

//public static object lockobj = new object();

public Form1()
{
InitializeComponent();

for (int i = 0; i < dots.Length; ++i)
{
dots[i] = new Dot(i, this.CreateGraphics());
}
}

/// <summary>
/// 变更活动点
/// </summary>
//public static void NextDot()
//{
// lock (lockobj)
// {
// if (CurrentDotIndex < 4)
// ++CurrentDotIndex;
// else
// CurrentDotIndex = 0;
// }
//}

private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < dots.Length; ++i)
{
dots[i].Start();
}
}

}//end of class Form1



/// <summary>
/// 表示一个“点”
/// </summary>
internal sealed class Dot
{
readonly int m_index;
/// <summary>
/// 点位于点数组中的索引(0~4)
/// </summary>
public int Index
{
get { return m_index; }
}

bool m_isVisible;
/// <summary>
/// 是否可见
/// </summary>
public bool IsVisible
{
get { return m_isVisible; }
set { m_isVisible = value; }
}

//点坐标
Point m_location;
//角度
int m_angle;
//定时器
System.Timers.Timer m_tmr;
//图形
Graphics m_graphics;

/// <summary>
/// 构造点
/// </summary>
/// <param name="index">点位于点数组中的索引(0~4)</param>
/// <param name="g">图形</param>
public Dot(int index, Graphics g)
{
if (index < 0 || index > 4)
throw new IndexOutOfRangeException("索引必须在0~4之间");

m_index = index;
m_isVisible = false;
m_tmr = new System.Timers.Timer(30);
m_tmr.Elapsed += m_tmr_Elapsed;
m_graphics = g;
m_angle = 312 - m_index * 12;
}

void m_tmr_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//if (this.InvokeRequired)
//{
// DrawDelegate draw = Draw;
// this.BeginInvoke(draw);
//}

Console.WriteLine(m_tmr.Interval);

//if (Form1.CurrentDotIndex == m_index)
//{
//Common.DrawDelegate drawdele = Draw;
//drawdele();
Draw();

m_angle = m_angle >= 356 ? 0 : m_angle + 4;

#region ChangeTimerInterval

if (m_angle >= Common.slowAngle_1 || m_angle < Common.quickAngle_1)//因涉及到359变0,此处为||而不是&&
{
if (m_tmr.Interval > 2)
{
m_tmr.Interval -= 2;
}
else if (m_tmr.Interval > 0.1)
{
m_tmr.Interval -= 0.1;
}
else if (m_tmr.Interval > 0.01)
{
m_tmr.Interval -= 0.01;
}
else if (m_tmr.Interval > 0.001)
{
m_tmr.Interval -= 0.001;
}
}
else if (m_angle >= Common.quickAngle_1 && m_angle < Common.slowAngle_2)
{
if (m_tmr.Interval < 30)
{
++m_tmr.Interval;
}
}
else if (m_angle >= Common.slowAngle_2 && m_angle < Common.quickAngle_2)
{
if (m_tmr.Interval > 2)
{
m_tmr.Interval -= 2;
}
else if (m_tmr.Interval > 0.1)
{
m_tmr.Interval -= 0.1;
}
else if (m_tmr.Interval > 0.01)
{
m_tmr.Interval -= 0.01;
}
else if (m_tmr.Interval > 0.001)
{
m_tmr.Interval -= 0.001;
}
}
else if (m_angle >= Common.quickAngle_2 && m_angle < Common.slowAngle_1)
{
if (m_tmr.Interval < 30)
{
++m_tmr.Interval;
}
}
#endregion

// Form1.NextDot();
//}
}

public void Start()
{
if (!m_tmr.Enabled)
m_tmr.Start();
}

public void Stop()
{
if (m_tmr.Enabled)
m_tmr.Stop();
}

/// <summary>
/// 绘制
/// </summary>
private void Draw()
{
lock (m_graphics)
{
Rectangle rect = new Rectangle(m_location, new Size(3, 3));

//m_graphics.DrawEllipse(Pens.RoyalBlue, rect);
m_graphics.FillEllipse(Brushes.RoyalBlue, rect);//Erase last frame

m_location = Common.GetDotLocationByAngle(25, m_angle);

rect = new Rectangle(m_location, new Size(3, 3));
m_graphics.FillEllipse(Brushes.White, rect);
}
}

}//end of class Dot


我用一个Dot对象表示一个“点”,每个Dot有自己的timer,但共用一个由窗体创建的Graphics,线程争用问题导致点的顺序会乱,求各位大神给个解决方案……万谢……
PS:各位大神可以新建个winform运行下,错位在转一圈之后就很明显了
...全文

相关推荐

C# Timer深度解析:从基础使用到高级调度实战指南

定时任务调度是软件开发中的核心概念,它允许程序在特定时间或周期性地执行代码逻辑。其原理通常基于操作系统或运行时提供的计时器机制,通过回调函数或事件驱动模型触发预定操作。在C#生态中,这一技术价值体现在构建可靠的后台服务、实现自动化作业以及优化资源管理等方面。无论是桌面应用的UI更新、服务器端的数据处理,还是游戏中的冷却计时,精准的调度都至关重要。本文聚焦于C#中多种Timer类的选择与避坑,特别是针对**System.Threading.Timer**和**System.Timers.Timer**的线程模

weixin_30653023

C#高精度计时器与System.Threading.Timer应用指南

在软件开发中,计时器是实现任务调度和时间控制的核心组件。System.Threading.Timer作为.NET框架中的轻量级计时器,采用线程池机制执行回调,避免了UI线程阻塞问题。其底层原理基于系统时钟中断,典型精度为15毫秒,适用于后台任务处理等场景。对于更高精度需求,可结合Stopwatch类实现微秒级测量,或使用自旋等待技术达到纳秒级延迟控制。这些技术在实时数据采集、游戏开发、金融交易等对时间敏感的应用中尤为重要。通过合理的线程优先级设置和误差补偿算法,开发者可以构建出高稳定性的定时任务系统。

weixin_30376083

上位机定时器设计:多Timer任务拆分与最佳实践

定时器是编程中常用的时间触发机制,用于在指定间隔执行任务。在上位机开发中,定时器设计直接影响系统稳定性与响应速度。如果所有任务共用一个定时器,容易出现界面卡顿、数据丢帧、任务互相干扰等问题。通过理解不同定时器(如System.Windows.Forms.Timer、System.Timers.Timer)的适用场景,按任务频率拆分定时器、为回调设置时间预算、使用标志位防止重入,可构建高效的任务调度方案。C# WinForms/WPF环境下,结合状态机与队列模型,能进一步优化多任务处理。本文从基础概念出发,分

weixin_30363981

正交拉丁超立方(OLHC)分组与实验设计(DOE)评估的优化Python实现.rar

正交拉丁超立方(OLHC)分组与实验设计(DOE)评估的优化Python实现.rar

天天Matlab科研工作室

Java微服务如何拆解审计日志查询服务

标题:Java微服务如何拆解审计日志查询服务 内容概要:围绕缓存策略、任务调度、回压控制和审计追踪,拆解Java微服务如何拆解审计日志查询服务的实现细节。 xdronline.com xdrea.com 9g.xinmei6.com xinghaohuanbao.com m.xiker66.com

2601_97068614
评论 4
收藏 已收藏
分享
返回顶部
__Meow
C# 111,128 成员 642,536 内容