Reputation: 353
i am extremely new to C# so excuse me if i don't explain this well.
i'm retrieving images from my computer camera, and along with displaying them in a PictureBox, i'm encoding them to jpegs and sending them to a shared dictionary. here's my code:
void CurrentCamera_OnImageCaptured(object sender, CameraEventArgs e)
{
this.pictureBoxMe.Image = e.Image;
if (myName != "" && Form1.PicSent)
{
SendPic sendP = new SendPic((Image)e.Image.Clone());
new System.Threading.Thread(new System.Threading.ThreadStart(sendP.send)).Start();
}
}
public class SendPic
{
Image im;
public SendPic (Image im)
{
this.im = im;
}
public void send(){
Form1.PicSent = false;
var memoryStream = new MemoryStream();
im.Save(memoryStream, ImageFormat.Jpeg);
var byteArray = memoryStream.ToArray();
Form1.sd["/" + myName + "/video"] = byteArray;
memoryStream.Close();
Form1.PicSent = true;
}
}
the problem is that i'm getting the "Object is currently in use elsewhere." error on the line: SendPic sendP = new SendPic((Image)e.Image.Clone());
based on other forum posts i've found, i already changed it so that the image is passed to the thread, and so that it's a clone. however i'm still getting the same error (though it lasts longer before crashing now).
i read something about locking? how do i implement that in this case? or is there something else i need to do?
thanks.
Upvotes: 2
Views: 3023
Reputation: 15794
One thing that catches my eye is that the SendPic
class accesses your dictionary asynchronously (the line: Form1.sd["/" + myName + "/video"] = byteArray;
).
However, dictionaries and hashtables are not guaranteed to be thread-safe for write operations. You should be safe if you make the code accessing the dictionary to be thread-safe. A simple lock
would be a way to start.
Sort of like this:
public class SendPic
{
private object lockobj = new object();
// .... whatever other code ...
public void send()
{
// .... whatever previous code ...
lock(lockobj)
{
// assuming that the sd dictionary already has the relevant key
// otherwise you'd need to do a Form1.sd.Add(key, byteArray)
Form1.sd["/" + myName + "/video"] = byteArray;
}
// .... whatever following code ...
}
}
Thread Safety
A Dictionary<(Of <(TKey, TValue>)>) can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure. In the rare case where an enumeration contends with write accesses, the collection must be locked during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.
Upvotes: 1
Reputation: 941407
It behaves as though the OnImageCaptured method runs on a thread. Which isn't unlikely for camera interfaces. Set a breakpoint and use the debugger's Debug + Windows + Threads window to see what thread is running this code.
The failure mode is then that the UI thread is accessing the image to paint the picture box, simultaneously with this worker thread calling Clone(). GDI+ does not permit two threads accessing the same image object at the same time. It would indeed be flaky, no telling at what exact moment in the time the UI thread starts painting. PicSent is another accident waiting to happen.
Upvotes: 3