c#线程间共享的数据不会更新
本文关键字:更新 数据 线程 共享 | 更新日期: 2023-09-27 18:16:16
我要做的是我在gui线程中绘制图像,我有另一个线程,它对具有图像的对象进行了理想化,并每秒将其发送到tcp套接字。paint事件中的图像正在改变,但它在tcp线程中没有改变。下面是修改后的代码:
// GUI class:
private static readonly object lock_obj = new object();
private GraphicsServerReceiver server;
private Bitmap gl_image;
private void checkBoxActivateBroadcast_CheckedChanged(object sender, EventArgs e)
{
if (checkBoxActivateBroadcast.Checked)
{
this.server = new GraphicsServerReceiver(SERVER_PORT, gl_image);
}
}
private void glControl1_Paint(object sender, PaintEventArgs e)
{
// do some drawing
lock (lock_obj)
{
gl_image = TakeScreenshot();
}
}
public Bitmap TakeScreenshot()
{
if (GraphicsContext.CurrentContext == null)
throw new GraphicsContextMissingException();
int w = glControl1.ClientSize.Width;
int h = glControl1.ClientSize.Height;
Bitmap bmp = new Bitmap(w, h);
System.Drawing.Imaging.BitmapData data =
bmp.LockBits(glControl1.ClientRectangle, System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
GL.ReadPixels(0, 0, glControl1.ClientSize.Width, glControl1.ClientSize.Height, PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0);
bmp.UnlockBits(data);
bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
return bmp;
}
#----------------
# the GraphicsServerReceiver class:
private Bitmap gl_image;
private static readonly object lock_obj = new object();
public GraphicsServerReceiver(int port, Bitmap gl_image)
{
this.port = port;
this.gl_image = gl_image;
this.tcpListener = new TcpListener(IPAddress.Loopback, port);
this.tcpListener.Start();
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
while (true)
{
try
{
TcpClient client = this.tcpListener.AcceptTcpClient();
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
catch (Exception ex)
{
Console.WriteLine("Error: Server was stopped so program failed to listen to clients. " + ex.Message);
}
}
}
private void HandleClientComm(object client)
{
byte[] buffer;
lock(lock_obj)
{
databag.img = gl_image;
buffer = Serializer.ObjectToByteArray(databag);
}
// send the data in buffer...
}
这一定是一个多线程问题,但我没有看到它。我在这两个类中使用了不同的锁对象。会是这个原因吗?
新增信息:下面是一个文件中的完整代码,它再现了没有paint事件的问题:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private static readonly object lock_obj = new object();
private Bitmap gl_image;
private GraphicsServerReceiver server;
private bool server_running = false;
public Form1()
{
InitializeComponent();
}
private void btn1_Click(object sender, EventArgs e)
{
if (!server_running)
{
lock (lock_obj)
{
gl_image = new Bitmap("C:/temp/x.bmp");
}
this.server = new GraphicsServerReceiver(gl_image);
btn1.Text = "stop";
}
else
{
server.stop();
btn1.Text = "start";
}
server_running = !server_running;
}
private void btn2_Click(object sender, EventArgs e)
{ // change the image
lock (lock_obj)
{
// draw a line:
using (var graphics = Graphics.FromImage(gl_image))
{
Pen blackPen = new Pen(Color.Black, 3);
graphics.DrawLine(blackPen, 0, 0, 50, 50);
}
gl_image.Save("C:/temp/changed.bmp");
}
}
}
class GraphicsServerReceiver
{
private Bitmap gl_image;
private static readonly object lock_obj = new object();
private Thread listenThread;
public void stop()
{
listenThread.Abort();
listenThread.Join(1);
}
public GraphicsServerReceiver(Bitmap gl_image)
{
this.gl_image = gl_image;
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
try
{
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start("some param");
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
private void HandleClientComm(object useless_obj)
{
while (listenThread.IsAlive)
{
lock (lock_obj)
{
gl_image.Save("C:/temp/out.bmp");
}
Thread.Sleep(1000);
}
}
}
}
你正在使用OnPaint事件来重新绘制图像。除非你最小化你的窗口,移动或做一些内部触发WM_PAINT的事情,否则你的图像将永远不会被绘制出来。
一个建议是当你从服务器收到图像后,你调用:
yourControl.Invoke(InvalidateControl);
public void InvalidateControl(){
yourControl.Invalidate();
}
"Invoke"需要从其他线程更改GUI中的某些内容。你也可以使用图像控件来更新图像,而不是使用OnPaint事件。
解决方案:而不是使用gl_image,然后把锁在它,我做了一个update_image方法在我的服务器,我调用它每当我画一些新的东西。这工作。
然而,我仍然不知道为什么我的参考资料没有在我第一次尝试的另一种方法中得到更新,所以如果有人能正确地解释这一点,我将感激并投票。