文章出處

 綜述 : 本文章介紹.Net 環境下C# 通過托管C++調用本地C++ Dll文件, 示例環境為:VS2010, .Net4.0, Win7. 具體事例為測試C++, C#, 及C#調用本地C++Dll文件進行浮點運算效率的一部分. 如果需要查看三者的效率, 請繼續閱讀下面的文章.

 

a 創建本地CPP類庫

1. 創建本地CPP的Dll ---->EfficiencyNativeCPPDLL

2. 點擊下一步 注意選擇為DLL(D)項, 然后選擇完成.

3.書寫DLL文件

3.1 

EfficiencyNativeCppDll.h

#pragma once

#ifndef GoWin_DLL_CLASS_EXPORTS
//該類可導出
#define GoWin_DLL_CLASS __declspec(dllexport)
#else
//該類可導入
#define GoWin_DLL_CLASS __declspec(dllimport)
#endif
#define NPARTS 1000
#define DIMS 3

class GoWin_DLL_CLASS EfficiencyNativeCppDll
{
public:
	EfficiencyNativeCppDll(void);
	~EfficiencyNativeCppDll(void);
	
	void InitPositions();
	void UpdatePositions();
	double ComputePot();
	double Pot;
private:
	double _r[DIMS][NPARTS];
};


3.2

EfficiencyNativeCppDll.cpp

#define WIN32_LEAN_AND_MEAN             //  從 Windows 頭文件中排除極少使用的信息
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>


EfficiencyNativeCppDll::EfficiencyNativeCppDll(void)
{
	Pot = 0;
}


EfficiencyNativeCppDll::~EfficiencyNativeCppDll(void)
{
	printf("~EfficiencyNativeCppDll is called");
}

void EfficiencyNativeCppDll::InitPositions()
{
	for(int i = 0; i < DIMS; i++)
	{
		for (int j = 0; j < NPARTS; j++)
		{
			_r[i][j] = 0.5 + (double)rand()/RAND_MAX;
		}
	}
}

void EfficiencyNativeCppDll::UpdatePositions()
{
	for(int i = 0; i < DIMS; i++)
	{
		for (int j = 0; j < NPARTS; j++)
		{
			_r[i][j] -= 0.5 + (double)rand()/RAND_MAX;
		}
	}
}

double EfficiencyNativeCppDll::ComputePot()
{
	double distx, disty, distz, dist;
	double pot;
	distx = 0;
	disty = 0;
	distz = 0;
	pot = 0;

	for(int i=0; i<NPARTS; i++ ) 
	{
		for(int j=0; j<i-1; j++ ) 
		{
			distx = pow( (_r[0][j] - _r[0][i]), 2 );
			disty = pow( (_r[1][j] - _r[1][i]), 2 );
			distz = pow( (_r[2][j] - _r[2][i]), 2 );
			dist = sqrt( distx + disty + distz );
			pot += 1.0 / dist;
		}		
	}

	this->Pot = pot;

	return pot;
}

在Release狀態下生成, 會得到 EfficiencyNativeCPPDLL.dll 和 EfficiencyNativeCPPDLL.lib兩種文件 其中EfficiencyNativeCPPDLL.dll用于后面的CLR/C++調用; 而EfficiencyNativeCPPDLL.lib則用于Native C++的調用; 這在效率對比一文中會用到.

b 創建C++/CLI類庫

1. 添加新建項目 EfficiencyCLRWrapper

2. 項目 EfficiencyCLRWrapper需要對項目EfficiencyNativeCPPDLL中的EfficiencyNativeCppDll.h 和 EfficiencyCLRWrapper.dll引用

2.1 引用EfficiencyNativeCppDll.h

有兩種方式, 可任選一種

a) 將EfficiencyNativeCppDll.h直接復制到 項目 EfficiencyCLRWrapper中, 這很簡單 不再描述

b)  更改 項目 EfficiencyCLRWrapper屬性設置中包換目錄選項, 以包含文件EfficiencyNativeCppDll.h

      b.1) 看到右側的包含目錄了嗎? 點擊后選擇 編輯

      

     b.2)   我這里選擇了把EfficiencyNativeCPPDLL文件夾及項目EfficiencyNativeCPPDLL的Release文件夾均包含在內了    

     

 

2.2 引用完成后書寫C++/CLR代碼

2.2.1 頭文件

EfficiencyCLRWrapper.h

#pragma once
#include "EfficiencyNativeCppDll.h"
#define  GoWin_DLL_CLASS

using namespace System;

namespace EfficiencyCLRWrapper {

	public ref class CLRWrapper
	{
	private:
		EfficiencyNativeCppDll * _pNtvCppPro;
	public:	
		CLRWrapper(void);
		~CLRWrapper(void);
		void InitPositions();
		void UpdatePositions();
		double ComputePot();
		property double Pot
		{
		double get();
		void set(double value);
		}
	};
}

2.2.2 主體文件

#include "EfficiencyCLRWrapper.h"
using namespace EfficiencyCLRWrapper;

CLRWrapper::CLRWrapper(){ this->_pNtvCppPro = new EfficiencyNativeCppDll();}
CLRWrapper::~CLRWrapper(){}

double CLRWrapper::ComputePot()
{
	return this->_pNtvCppPro->ComputePot();
}

void CLRWrapper::InitPositions()
{
	this->_pNtvCppPro->InitPositions();
}

void CLRWrapper::UpdatePositions()
{
	this->_pNtvCppPro->UpdatePositions();
}


double CLRWrapper::Pot::get()
{
	return this->_pNtvCppPro->Pot;
}

void CLRWrapper::Pot::set(double value)
{
	this->_pNtvCppPro->Pot = value;
}

2.2.3 將形成如下樹結構:

 

3. 千萬不要忘記的一點就是在項目EfficiencyCLRWrapper中對EfficiencyNativeCPPDLL的引用, 否則依舊無法生成, 如圖:

    

4 這個時候 對項目EfficiencyCLRWrapper在Release下生成則可以得到 文件 CLRCPPWrapper.dll

C 創建C# 控制臺應用程序

1 添加C#項目 ConsoleEfficiencyCSInvokeCLRDll

2.  添加對項目 EfficiencyCLRWrapper的引用
     

3. 因項目ConsoleEfficiencyCSInvokeCLRDll須間接調用EfficiencyNativeCPPDLL.dll因此 跟上面相同可用兩種方法解決

可任選其一

a) 將以生成的EfficiencyNativeCPPDLL.dll復制到項目ConsoleEfficiencyCSInvokeCLRDll的bin/Release文件夾下 不再具體描述

b) 添加項目ConsoleEfficiencyCSInvokeCLRDll屬性中調試中的工作目錄 如圖:

   

 

4.  在Program.cs文件中做CS的調用

  

namespace EfficiencyCSInvokeCLRDll
{
    class Program
    {
        static void Main(string[] args)
        {
            CLRWrapper provider = new CLRWrapper();
            const int NITER = 201;
            
            provider.InitPositions();
            provider.UpdatePositions();

            int start = Environment.TickCount;
            for (int i = 0; i < NITER; i++)
            {
                provider.Pot = 0.0;

                //低效模式
                /*provider.ComputePot();
                if (i % 10 == 0)
                    Console.WriteLine("{0}: Potential: \t {1}", i, provider.Pot());
                 */

                //高效模式                
                if (i % 10 == 0)
                    Console.WriteLine("{0}: Potential: \t {1}", i, provider.ComputePot());
                provider.UpdatePositions();
                 
            }
            int stop = Environment.TickCount;

            Console.WriteLine("Seconds = {0,10}", (double)(stop - start) / 1000);

            Console.ReadKey();
        }
    }
}



運行結果: 

  

 

 

結果一般在0.240至00.281之間

硬件環境:  Inter(R) Core(TM)2 Duo CPU P8700 @ 2.53GHz 2.53GHz RAM 共4G(2.46GB可用)

 

疑問:

這里面有兩點疑問

1. 在CS調用中標出的高效模式和低效模式; 無非一個是直接調用函數返回值一個是調用函數后讀取屬性, 但是執行效率相差接近10倍.

2. 在C++/CLR中紅色表示的構造函數中申請的內存不曉得何時釋放.


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()