【问题标题】:image save Attempted to read or write protected memory error图像保存尝试读取或写入受保护的内存错误
【发布时间】:2018-02-23 15:14:53
【问题描述】:

我正在拼命地为我的代码寻找解决方案。我使用 backgroundworker 在线程中运行它。并且 img.Save 经常(并非总是)给出此错误。

image1.Save(ms1, imageCodecInfo, parametreler);

试图读取或写入受保护的内存。这通常是一个 指示其他内存已损坏。

在 System.Drawing.SafeNativeMethods.Gdip.GdipSaveImageToStream(HandleRef 图像、IStream 流、Guid 和 classId、HandleRef 编码器参数)在 System.Drawing.Image.Save(Stream 流,ImageCodecInfo 编码器, 编码器参数编码器参数)在 Project.Forms.Degerlendirme.EditProductPhotosForm.backgroundWorker_uploader2_DoWork(对象 发件人,DoWorkEventArgs e) 在 C:\Users\Umut\NETProjects\Project\Forms\Katalog\EditProductPhotosForm.cs:line 654 在 System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
在 System.ComponentModel.BackgroundWorker.WorkerThreadStart(对象 论点)在 System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, 对象服务器, Object[]& outArgs) 在 System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(IMessage 味精,IMessageSink 回复Sink)在 System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.ThreadPoolCallBack(对象 o) 在 System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(对象 州)在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext、ContextCallback 回调、对象状态、布尔值 preserveSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext、ContextCallback 回调、对象状态、布尔值 preserveSyncCtx) 在 System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() 在 System.Threading.ThreadPoolWorkQueue.Dispatch() 在 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

我阅读并尝试了每篇文章,但没有一个对我有帮助。我想我错过了一点。这是我的代码。

    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] };
                }
            }
        }
    }

这就是我对这个后台工作人员的称呼。我有6个,他们的dowork事件几乎一样。

       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();

【问题讨论】:

  • 为什么你有一个 lock 语句 - 没有其他线程执行此代码,所以不需要任何同步?
  • @auburg 其实我有不同的线程。我已经更改了变量名,我尝试过没有它,但它没有改变
  • 如果你锁定的不是图像而是一个虚拟对象,例如 lock(lockObj) - 请参阅 docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
  • omg 使用类而不是对象数组,你在严重滥用拳击
  • @MichaelRandall 我已经先这样做了,但是在整天遇到错误之后,我尝试了这种方式来查看它是否会改变

标签: c# multithreading image


【解决方案1】:

刚刚查看了文档:MS post on GDI+ and concurrency

根据该帖子,您不能同时使用 GDI+,但可以改为使用 WPF 进行映像操作。您的所有 GDI+ 操作都有对应的 WPF,但您必须四处看看如何做到这一点。

编辑:或者,作为一种变通方法,锁定一个静态对象以有效地序列化 GDI+ 的所有使用

static object _syncRoot = new object();

并在您的免费工作线程的锁定语句中使用它

lock (_syncRoot)

That syncRoot naming is a bit of a pattern these days

编辑2:如果您可以确保多个线程仅使用_syncRoot 的一个实例,则不需要static_syncRoot 可以是也启动后台线程的类的私有成员。

【讨论】:

  • 嗨,克里斯,它工作了 5-6 次,然后在第 7 次没有工作。再次出现同样的错误
  • @smoothumut 你有新的异常/调用堆栈吗?
  • 您好,再次感谢您的帮助。看起来它正在工作,但我不确定。我确实得到了一次,现在我尝试了很多次,但还没有得到任何。那是个好消息,但我只能在明天检查。我会让你知道进展情况。再次感谢我的朋友。
  • 嗨,克里斯,我在相同的堆栈跟踪中遇到了同样的错误。但我已经成功运行了 10 次左右。但是后来我不知道为什么它会给出同样的错误
  • @smoothumut 恐怕解决方法还不够好,您将不得不使用相当于保存 Jpeg 的 WPF。
猜你喜欢
  • 2010-10-10
  • 2010-12-27
  • 2010-11-10
  • 1970-01-01
  • 1970-01-01
  • 2011-09-16
相关资源
最近更新 更多