C#摄像头定时存帧异常:‘对象正被其他进程使用’排查与修复
问题成因分析
Let's break down why that random "Object in use by another process" exception is popping up:
- Thread Safety Conflicts: The
NewFrameevent fires on a background thread, but your original code modifiespictureBox1.Imagedirectly from that thread. This creates race conditions where the UI thread and background thread might access the same Bitmap instance simultaneously. - Bitmap Resource Locking: When you called
pictureBox2.Image.Save(), the Bitmap was still referenced by the picture box control. The UI could be trying to render the image while the save operation accesses its resources, leading to a lock conflict. - Incomplete Resource Cleanup: You cloned Bitmaps but didn't always dispose of them properly. Over time, leaked resource handles cause unexpected locks.
- Unreliable Synchronization: The
blncapturingflag is a simple boolean without proper thread synchronization, so it might not prevent concurrent execution of the capture logic reliably.
代码修改方案
Here's the fixed code with key improvements explained:
public partial class Form1 : Form { private FilterInfoCollection CaptureDevices; private VideoCaptureDevice videoSource; private readonly object _syncLock = new object(); // For thread-safe execution bool blncapturing; public Form1() { InitializeComponent(); timer1.Enabled = false; timer1.Interval = 5000; blncapturing = false; } private void button1_Click(object sender, EventArgs e) { videoSource = new VideoCaptureDevice(CaptureDevices[comboBox1.SelectedIndex].MonikerString); videoSource.NewFrame += VideoSource_NewFrame; videoSource.Start(); timer1.Enabled = true; } private void VideoSource_NewFrame(object sender, NewFrameEventArgs eventArgs) { // Marshal UI updates to the UI thread to avoid cross-thread issues if (pictureBox1.InvokeRequired) { pictureBox1.Invoke(new Action(() => UpdatePictureBox(pictureBox1, (Bitmap)eventArgs.Frame.Clone()))); } else { UpdatePictureBox(pictureBox1, (Bitmap)eventArgs.Frame.Clone()); } } // Helper to safely update picture boxes and clean up old images private void UpdatePictureBox(PictureBox pb, Bitmap newImage) { if (pb.Image != null) { ((IDisposable)pb.Image).Dispose(); } pb.Image = newImage; } private void Form1_Load_1(object sender, EventArgs e) { CaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice); foreach (FilterInfo Device in CaptureDevices) { comboBox1.Items.Add(Device.Name); } comboBox1.SelectedIndex = 0; videoSource = new VideoCaptureDevice(); } private void button2_Click(object sender, EventArgs e) { videoSource?.Stop(); UpdatePictureBox(pictureBox1, null); UpdatePictureBox(pictureBox2, null); } private void button3_Click(object sender, EventArgs e) { CaptureAndSaveFrame(); } private void button4_Click(object sender, EventArgs e) { videoSource?.Stop(); Application.Exit(); } private void timer1_Tick(object sender, EventArgs e) { CaptureAndSaveFrame(); } private void CaptureAndSaveFrame() { lock (_syncLock) // Ensure only one capture runs at a time { if (blncapturing || pictureBox1.Image == null) return; blncapturing = true; try { // Create an isolated copy of the frame to avoid UI resource conflicts using (Bitmap frameCopy = new Bitmap((Bitmap)pictureBox1.Image.Clone())) { string savePath = string.Format(@"C:\Users\echristo\Desktop\trial\Snapshot_{0:yyyyMMdd_hhmmss.fff}.jpg", DateTime.Now); frameCopy.Save(savePath, System.Drawing.Imaging.ImageFormat.Jpeg); // Update pictureBox2 safely on the UI thread if (pictureBox2.InvokeRequired) { pictureBox2.Invoke(new Action(() => UpdatePictureBox(pictureBox2, (Bitmap)frameCopy.Clone()))); } else { UpdatePictureBox(pictureBox2, (Bitmap)frameCopy.Clone()); } } } catch (Exception ex) { MessageBox.Show($"Capture error: {ex.Message}"); } finally { blncapturing = false; // Reset flag even if an error occurs } } } }
Key Fixes:
- Thread-Safe UI Operations: All picture box updates use
Invoketo run on the UI thread, eliminating cross-thread race conditions. - Isolated Frame Copies: We save a separate Bitmap copy (wrapped in
usingto auto-dispose) instead of the UI-bound image, preventing resource locks. - Reliable Synchronization: The
lockobject ensures only one capture operation runs at a time, making theblncapturingflag fully effective. - Clean Resource Management: The
UpdatePictureBoxhelper guarantees old Bitmaps are disposed before replacement, preventing leaks. - Robust Error Handling: The
finallyblock ensures the capture flag is reset even if an exception occurs, so the feature doesn't get stuck.
内容的提问来源于stack exchange,提问作者Terry24
相关产品推荐
相关产品推荐

