Reputation: 3491
I am desperatly finding a solution for my code. I run it in a thread using backgroundworker. and img.Save frequently(not always) gives this error.
image1.Save(ms1, imageCodecInfo, parametreler);
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at System.Drawing.SafeNativeMethods.Gdip.GdipSaveImageToStream(HandleRef image, IStream stream, Guid& classId, HandleRef encoderParams) at System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams) at Project.Forms.Degerlendirme.EditProductPhotosForm.backgroundWorker_uploader2_DoWork(Object sender, DoWorkEventArgs e) in C:\Users\Umut\NETProjects\Project\Forms\Katalog\EditProductPhotosForm.cs:line 654 at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument) at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Object[]& outArgs) at System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(IMessage msg, IMessageSink replySink) at System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.ThreadPoolCallBack(Object o) at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
I read and tried every post, but none of them helped me. I guess I am missing a point. Here is my code.
private void backgroundWorker_uploader1_DoWork(object sender, DoWorkEventArgs e)
{
object[] parameters = e.Argument as object[];
string fileName = parameters[1] as string;
string filePath = parameters[4] as string;
using (Image image1 = parameters[0] as Image)
using (MemoryStream ms1 = new MemoryStream())
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo imageCodecInfo = null;
foreach (ImageCodecInfo codec in codecs)
{
if (codec.MimeType == "image/jpeg")
imageCodecInfo = codec;
}
EncoderParameters parametreler = new EncoderParameters(1);
parametreler.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)100);
//Object imageLock1 = new Object();
lock (image1)
{
image1.Save(ms1, imageCodecInfo, parametreler);
}
using (Image img1 = Image.FromStream(ms1))
{
bool sonuc = HelperActions.UploadImgToFTPfromImage(fileName, img1);
if (sonuc == true)
{
e.Result = new object[6] { this, prevForm, true, (int)parameters[5], (int)parameters[2], (int)parameters[3] };
}
else
{
e.Result = new object[6] { this, prevForm, false, (int)parameters[5], (int)parameters[2], (int)parameters[3] };
}
}
}
}
this is how I call this backgroundworker. I have 6 of them, their dowork event almost same.
for (int i = 0; i < mappings.Count; i++)
{
Picture picture = mappings[i].Picture as Picture;
if (picture == null)
continue;
mappings[i].DisplayOrder = (int)numUpDowns[i].Value - 1;
entities.Product_Picture_Mapping.AddOrUpdate(mappings[i]);
string fileName = HelperActions.CreateImgFileName(picture);
string filePath = "";
object obje11 = picEdits[i].Image as Image;
object obje12 = fileName;
object obje13 = picture.Id;
object obje14 = i + 1;
object obje15 = filePath;
object obje16 = productId;
object[] parameters = new object[6] { obje11, obje12, obje13, obje14, obje15, obje16 };
try
{
switch (i)
{
case 0:
backWorker1_uploader.RunWorkerAsync(parameters);
break;
case 1:
backWorker2_uploader.RunWorkerAsync(parameters);
break;
case 2:
backWorker3_uploader.RunWorkerAsync(parameters);
break;
case 3:
backWorker4_uploader.RunWorkerAsync(parameters);
break;
case 4:
backWorker5_uploader.RunWorkerAsync(parameters);
break;
case 5:
backWorker6_uploader.RunWorkerAsync(parameters);
break;
default:
break;
}
}
catch (Exception ex)
{
if (!backgroundWorkerYedek.IsBusy)
{
backgroundWorkerYedek.RunWorkerAsync(parameters);
Console.WriteLine("Yedek Çalıştırıldı");
}
else
{
MessageBox.Show(i + " nolu - " + ex.Message);
}
}
System.Threading.Thread.Sleep(200);
}
entities.SaveChanges();
Upvotes: 0
Views: 591
Reputation: 5037
Just looked in the docs: MS post on GDI+ and concurrency
According to that post, you cannot use GDI+ concurrently, but can instead use WPF for your imaging operations. All of your GDI+ operations do have WPF counterparts, but you'll have to look around on how to do that.
EDIT: Or, as a workaroud, lock on a static object to effectively serialize all usage of the GDI+
static object _syncRoot = new object();
And Use that in your lock statements for the bacground worker thread
lock (_syncRoot)
That syncRoot naming is a bit of a pattern these days
EDIT 2: you don't need the static
if you can ensure that only one single instance of _syncRoot
is being used by the multiple threads. The _syncRoot
can be a private member of the class that also starts the background threads.
Upvotes: 1