【发布时间】:2016-07-05 23:19:39
【问题描述】:
我是编码游戏的新手,所以我不太确定如何解决这个问题。我的代码从一个线程中提取信息,该线程从一个 9DOF 传感器中获取数据,该传感器以三个欧拉角的形式出现。然后使用该数据生成点,在绘图类的屏幕上从这些点开始制作一个圆。完美地工作了一段时间,但最终总是会给出这个异常,说在 System.Drawing.dll 中发生了一个未处理的“System.InvalidOperationException”类型的异常,附加信息表明该对象当前正在其他地方使用。在更多地探索并使用所绘制的内容之后,我得出了一个(可能不正确的)结论,即线程发送数据的速度比主代码渲染绘图的速度要快。我怎样才能防止这种情况?代码摘录如下。
private void button3_Click(object sender, EventArgs e)
{
//single node test
Nodes.NodesList.Add(new RazorIMU("COM7"));
Nodes.NodesList[0].StartCollection('e');
Nodes.NodesList[0].CapturedData += new RazorDataCaptured(Fusion_CapturedData);
public void Fusion_CapturedData(float[] data, float deltaT)
{
int centerX = (int)(300 + (5 / 3) * data[0] + 0.5);
int centerY = (int)(300 + (5 / 3) * data[1] + 0.5);
int endPointX = (int)(centerX + 25 * Math.Sin(Math.PI / 180 * data[2]) + 0.5);
int endPointY = (int)(centerY + 25 * Math.Cos(Math.PI / 180 * data[2]) + 0.5);
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
/*g.DrawLine(new Pen(Color.Yellow), 300, 0, 300, 600);
g.DrawLine(new Pen(Color.Yellow), 0, 300, 600, 300);
g.DrawLine(new Pen(Color.LightYellow), 150, 0, 150, 600);
g.DrawLine(new Pen(Color.LightYellow), 0, 150, 600, 150);
g.DrawLine(new Pen(Color.LightYellow), 450, 0, 450, 600);
g.DrawLine(new Pen(Color.LightYellow), 0, 450, 600, 450);*/
g.DrawEllipse(new Pen(Color.Green), centerX - 25, centerY - 25, 50, 50);
g.DrawLine(new Pen(Color.Green), centerX, centerY, endPointX, endPointY);
}
pictureBox1.Image = bmp;
}
这是主要代码。线程只是以接收到的速度发送信息,所以我认为我不需要把它放在这里,除非有人另有说明。
{ 公共委托 void RazorDataCaptured(float[] data, float deltaT);
/// <summary>
///
/// Object for Sparkfun's 9 Degrees of Freedom - Razor IMU
/// Product ID SEN-10736
/// https://www.sparkfun.com/products/10736
///
/// Running Sample Firmware
/// https://github.com/a1ronzo/SparkFun-9DOF-Razor-IMU-Test-Firmware
///
/// </summary>
public class RazorIMU : IDisposable
{
private SerialPort _com;
private static byte[] TOGGLE_AUTORUN = new byte[] { 0x1A };
public string Port { get; private set; }
private Thread _updater;
private string[] _parts;
public event RazorDataCaptured CapturedData = delegate { };
private float[] _data = new float[9];
private static bool running = false;
/// <summary>
/// Create a new instance of a 9DOF Razor IMU
/// </summary>
/// <param name="portName">Serial port name. Ex: COM1.</param>
public RazorIMU(string portName)
{
// Create and open the port connection.
_com = new SerialPort(portName, 57600, Parity.None, 8, StopBits.One);
_com.Open();
Port = portName;
// Set the IMU to automatically collect data if it has not done yet.
//Thread.Sleep(3000);
//_com.Write("#s00");
//_com.DiscardInBuffer();
}
/// <summary>
/// Start continuous collection of data.
/// </summary>
public void StartCollection(char dataType)
{
running = true;
if (dataType == 'r') _updater = new Thread(new ThreadStart(ContinuousCollect));
else if (dataType == 'q') _updater = new Thread(new ThreadStart(ContinuousCollectQuat));
else if (dataType == 'e') _updater = new Thread(new ThreadStart(ContinuousCollectEuler));
_updater.Start();
}
/// <summary>
/// Stop continuous collect of data.
/// </summary>
public void StopCollection()
{
if (_updater != null)
{
running = false;
_updater.Join();
_updater = null;
}
}
/// <summary>
/// This method is extremely important. It continously updates the data array.
/// Data is read and the change in time since the last read is calculated.
/// The CapturedData event is triggered, sending the new data and the change in time.
/// </summary>
private void ContinuousCollect()
{
_com.WriteLine("#osr"); //Sets sensor output data to raw.
_com.ReadLine(); //Discards first line if broken.
while (running) //Static Boolean that controls whether or not to keep running.
{
ReadDataRaw();
CapturedData(_data, 0.020F);
}
}
private void ContinuousCollectQuat()
{
_com.WriteLine("#ot"); //Sets sensor output data to quaternions.
_com.ReadLine(); //Discards first line if broken.
while (running) //Static Boolean that controls whether or not to keep running.
{
ReadDataQuat();
CapturedData(_data, 0.020F);
}
}
private void ContinuousCollectEuler()
{
_com.WriteLine("#ob"); //Sets sensor output data to quaternions.
_com.ReadLine(); //Discards first line if broken.
while (running) //Static Boolean that controls whether or not to keep running.
{
ReadDataEuler();
CapturedData(_data, 0.020F);
}
}
/// <summary>
/// Get a single sample of the 9DOF Razor IMU data.
/// <para>Format: [accel_x,accel_y,accel_z,gyro_x,gyro_y,gyro_z,mag_x,mag_y,mag_z]</para>
/// </summary>
/// <param name="result">double array of length 9 required.</param>
private void ReadDataRaw()
{
_parts = _com.ReadLine().Split(',');
if (_parts.Length == 9)
for (int i = 0; i < 9; i++)
_data[i] = float.Parse(_parts[i]);
}
private void ReadDataQuat()
{
_parts = _com.ReadLine().Split(',');
if (_parts.Length == 4)
for (int i = 0; i < 4; i++)
_data[i] = float.Parse(_parts[i]);
}
private void ReadDataEuler()
{
_parts = _com.ReadLine().Split(',');
if (_parts.Length == 3)
for (int i = 0; i < 3; i++)
_data[i] = float.Parse(_parts[i]);
}
/// <summary>
///
/// </summary>
public void Dispose()
{
StopCollection();
if (_com != null) //Make sure _com exists before closing it.
_com.Close();
_com = null;
_data = null;
_parts = null;
}
}
}
【问题讨论】:
-
线程如何导致重绘?可能是缺少
Invoke或同步(例如异步调用事件,然后在前一个事件完成之前过早再次调用它)。 -
我认为这正是它正在做的事情,因为当我更改绘制的行数时,它会影响它在抛出此异常之前运行的时间。
-
好吧,我对 Invoke 做了一些粗略的研究(同样,非常新,完全是自学的),但这似乎不能解决问题,因为数据是连续出现的溪流。似乎更多的是同步将是答案。它可以做些什么来解决这个问题?我想我需要一种方法来阻止我的 sn-p 代码完成并简单地从下一批数据重新开始。
-
你能展示从接收数据到出现在屏幕上的完整链吗?目前你只发布了一些绘图和使用 UI 的事件处理程序(所以它应该在 UI 线程中运行),但不清楚是谁引发了这个事件,如何以及何时。
-
好的,我试试看。
标签: c# multithreading drawing