从 C# 线程调用非托管代码

Posted

技术标签:

【中文标题】从 C# 线程调用非托管代码【英文标题】:Calling unmanaged code from a C# thread 【发布时间】:2011-02-26 22:25:13 【问题描述】:

我有一个非托管 C++ 库,为此我创建了一个托管 C++ 包装器。我现在正试图从 C# 调用它。到现在为止还挺好。但是,当我尝试从 C# 线程中调用相同的代码时,我会从非托管代码中得到异常:

表达式:向量下标超出范围

这甚至可能吗?我假设每个线程都会获得它自己的非托管类实例?

我已经搜索了很长时间以获取有关从线程内调用非托管代码的更多信息,但至少可以说信息似乎很少。

提前感谢您的帮助

C++ 包装器

// Managed wrapper
public ref class EllipseFit

   private:
       // Pointer to unmanaged class
   UnmanagedEllipseFit* _unmanagedEllipseFit;

   public:

       // Constructor & Destructor
   EllipseFit() 
   
       _unmanagedEllipseFit = new UnmanagedEllipseFit();
       

   ~EllipseFit() 
    
       delete _unmanagedEllipseFit; 
   

       List<Ellipse^>^ ProcessImage(array<Byte>^ image, int width, int height)
        
           pin_ptr<unsigned char> pimg = &image[0];
       _unmanagedEllipseFit->processsImage(pimg, width, height); 

           // Marshal the results... <edited>
       return ellipses;
       
;

C# 线程

    private void DcThread()
    
        EllipseFit ellipseFit = new EllipseFit();

        string fullPath = _fileList.GetNext();
        while (fullPath != null)
        
            // Load the image
            Bitmap bitmap = new Bitmap(fullPath);
            byte[] imageData = TsImage.ConvertBitmap(bitmap);

            // Process
            List<DcEllipse> ellipses = ellipseFit.ProcessImage(imageData, bitmap.Width, bitmap.Height);

            // Save the associated text file.. (Debug)
            TextWriter textFile = new StreamWriter(fullPath.Replace(".jpg", ".txt"));
            foreach (DcEllipse ellipse in ellipses)
                textFile.WriteLine(String.Format("0 1 2 3 4", ellipse.X, ellipse.Y, ellipse.MajorAxisLength, ellipse.MinorAxisLength, ellipse.Angle));
            textFile.Close();

            fullPath = _fileList.GetNext();
        
    

C# 线程启动

Thread t1 = new Thread(DcThread);
t1.Start();

【问题讨论】:

您将不得不展示一些 C++/CLI 代码让我们理解这一点。 * 编辑 * 只有当我有多个线程时才会出现异常。在它自己的一个线程中,没有其他线程,我没有看到任何异常。 您是否明确地为每个线程创建了单独的类实例?当托管包装类或非托管本机类不是为多线程设计时共享它们是一个很大的禁忌。 嗨,迈克,是的,我为每个线程创建了一个新的 EllipseFit 实例。很抱歉没有提前发布代码。 【参考方案1】:

.NET 中的托管类型遵循相同的规则,无论它们是用 C# 还是 C++/CLI 编写的。

虽然可以为每个线程创建 C++/CLI 类的新实例,但如果不告诉编译器这是你想要的,它不会自动发生。

编辑:查看代码,除了内存泄漏之外,我没有看到任何问题。 C++/CLI 类应该同时具有析构函数和终结函数,如下所示:

!EllipseFit() 
 
    delete _unmanagedEllipseFit; 
    _unmanagedElipseFit = nullptr;



~EllipseFit()  this->!EllipseFit(); 

至于崩溃——也许非托管代码使用静态或全局变量,因此不能从多个线程同时使用。

【讨论】:

嗨 Ben,我确实在每个线程中创建了托管包装器的实例。我只是不明白为什么如果每个线程都有自己的实例,当我运行多个线程时我会看到不同的行为.. 啊现在.. 我的非托管 C++ 代码中的一个全局变量似乎是问题所在。感谢您的帮助! @user:您可能还需要using 语句以确保对象得到及时处理。

以上是关于从 C# 线程调用非托管代码的主要内容,如果未能解决你的问题,请参考以下文章

从 C# 线程内的非托管 dll 运行函数

让非托管 c++ 代码调用调用 c# 代码的托管 c++ 代码

从托管 C# 代码调用非托管 C++ 代码以生成脱机域加入 blob

从 c# dll 调用/编组字符串到非托管代码

调试从非托管 C++ 调用的托管 .NET 代码

从非托管 c++ 调用 C# 函数(通过托管包装器)