System.Timer.Timer的lock争用问题

__Meow 2013-03-29 03:26:45
好奇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运行下,错位在转一圈之后就很明显了
...全文
149 4 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
MX_小市民 2013-03-30
  • 打赏
  • 举报
回复
我了个去啊,我也要帮咖啡胸顶起,顶起,顶起,顶起,顶起,顶起,顶起,顶起,顶起
__Meow 2013-03-29
  • 打赏
  • 举报
回复
自己顶起啊………………
__Meow 2013-03-29
  • 打赏
  • 举报
回复
不要沉啊………………不要沉啊………………
__Meow 2013-03-29
  • 打赏
  • 举报
回复
自己顶,求大神指点……

111,098

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧