C#调用DLL中非托管C++函数参数类型对照

C#调用DLL中非托管C++函数参数类型对照
C#调用DLL中非托管C++函数参数类型对照

对于一维数组,C#参数在基本类型前加ref或out,out表示有返回数据。

如调用c++的f(float[] a), 在c#中,为f(ref a).

对数据结构,

c++

struct SAMPLE_DA TA{

byte SampleID[255];

float V alue[6];

}

C#

[StructLayout(LayoutKind.Sequential)]

unsafe public struct SAMPLE_DA TA

{

[MarshalAs(UnmanagedType.ByV alArray, SizeConst = 255)]

public byte[] SampleID;

[MarshalAs(UnmanagedType.ByV alArray, SizeConst = 6)]

public float[] V alue;

}

以下是基本数据类型的对照。

[转自]https://www.360docs.net/doc/6d6701393.html,/blog/491410

使用C#调用了很多非托管的C++代码。

现在就把"C# 调用Dll中非托管C++代码时,函数参数的类型对照"这一问题做一个总结。

用这些关键字进行搜索,网上有不少这样那个的内容,比如下面这几个链接

C# 与C++ 数据类型对照(后三篇内容一样)

https://www.360docs.net/doc/6d6701393.html,/u/20090928/11/af7848c6-5071- 41aa-92e2-e8d626d6aefe.html

https://www.360docs.net/doc/6d6701393.html,/dz45693/archive/2009/09/26/45 98867.aspx

https://www.360docs.net/doc/6d6701393.html,/yiki/archive/2008/10/29/132 1848.html

https://www.360docs.net/doc/6d6701393.html,/okadler0518/archive/2009/06/2 2/4289679.aspx

但是上面的映射有时候会出现问题。

比如上面的帖子都将LPTSTR映射成String,

然而在处理GetWindowText 函数是,因为这个LPTSTR是为了要将结果带回来的返回值。

因此在这里使用String便行不通了,而需要使用StringBuffer。

注:GetWindowText的原型

如果问题的方法,仅仅是查看上面那几个链接,那么我一定不会写这篇博客。

我的主要目的是要介绍另外两种方法。

方法一:

查看Web版本的MSDN。

看看下面这两个连接,在Community Content部分都给出了C#,VB调用的原型。

当然,不是所有的函数对应的Community Content部分都有完整的事例。

但有的给出了一些常量的值,有的给出了一些结构体的定义,总之这部分内容还是具有参考价值。

注:安装在本机的MSDN没有Community Content这部分内容。

GetWindowText

https://www.360docs.net/doc/6d6701393.html,/en-us/library/ms633520%2 8VS.85%29.aspx

GetForegroundWindow

https://www.360docs.net/doc/6d6701393.html,/en-us/library/ms633505%2 8VS.85%29.aspx

方法二:

P/Invoke Interop Assistant

输入你想要的东西(Type,Constant,Procedure),他会自动生成相应的代码(C#,或VB)。

举例子说明。

当我要SHGetFileInfo调用这个函数是,需要用到类型:SHFileInfo

于是我在P/Invoke Interop Assistant查询类型SHFileInfo,便会得到下面结果:

[System.Runtime.InteropServices.StructLayoutAttrib

ute(https://www.360docs.net/doc/6d6701393.html,youtKind.Seque ntial,

CharSet=System.Runtime.InteropServices.CharSet.Uni code)]

publicstruct SHFILEINFOW {

/// HICON->HICON__*

public System.IntPtr hIcon;

/// int

publicint iIcon;

/// DWORD->unsigned int

publicuint dwAttributes;

/// WCHAR[260]

[System.Runtime.InteropServices.MarshalAsAttribute

(System.Runtime.InteropServices.UnmanagedType.ByV al TStr, SizeConst=260)]

publicstring szDisplayName;

/// WCHAR[80]

[System.Runtime.InteropServices.MarshalAsAttribute

(System.Runtime.InteropServices.UnmanagedType.ByV al TStr, SizeConst=80)] publicstring szTypeName;

}

[System.Runtime.InteropServices.StructLayoutAttrib

ute(https://www.360docs.net/doc/6d6701393.html,youtKind.Seque ntial,

CharSet=System.Runtime.InteropServices.CharSet.Uni code)] public struct SHFILEINFOW { /// HICON->HICON__* public System.IntPtr hIcon; /// int public int iIcon; /// DWORD->unsigned int public uint dwAttributes; /// WCHAR[260] [System.Runtime.InteropServices.MarshalAsAttribute

(System.Runtime.InteropServices.UnmanagedType.ByV al TStr, SizeConst=260)] public string szDisplayName; /// WCHAR[80]

[System.Runtime.InteropServices.MarshalAsAttribute

(System.Runtime.InteropServices.UnmanagedType.ByV al TStr, SizeConst=80)] public string szTypeName; }

再举一个例子。

对于前面提到的GetWindowText函数,如果在P/Invoke Interop Assistant的Procedure中进行查询的话。

也会得到下面的代码:

上面这段代码有经过我整理,自动生成的东西,可读性还是烧差一些,有冗余的东西。

尽管如此这一工具还是非常好用。

总结起来

配合这个工具,还有本文开头部分提到的C# 与C++ 数据类型对照表。

分析分析,查找查找,是在不行再GoogleGoogle。

在C#中调用非托管dll代码,还是很方便的。

方便起见,我也将《C# 与C++ 数据类型对照表》转载如下:

C# 调用Dll中非托管C++代码,函数参数的类型对照(2)

C++ C#

=====================================

WORD ushort

DWORD uint

UCHAR int/byte 大部分情况都可以使用int代替,而如果需要严格对齐的话则应该用bytebyte

UCHAR* string/IntPtr

unsigned char* [MarshalAs(UnmanagedType.LPArray)]byte[]/?

(Intptr)

char* string

LPCTSTR string

LPTSTR [MarshalAs(UnmanagedType.LPTStr)] string

long int

ulong uint

Handle IntPtr

HWND IntPtr

void* IntPtr

int int

int* ref int

*int IntPtr

unsigned int uint

COLORREF uint API与C#的数据类型对应关系表

API数据类型类型描述 C#类型 API数据类型类型描述 C#类型WORD 16位无符号整数 ushort CHAR 字符 char

LONG 32位无符号整数 int DWORDLONG 64位长整数 long

DWORD 32位无符号整数 uint HDC 设备描述表句柄 int

HANDLE 句柄,32位整数 int HGDIOBJ GDI对象句柄 int

UINT 32位无符号整数 uint HINSTANCE 实例句柄 int

BOOL 32位布尔型整数 bool HWM 窗口句柄 int

LPSTR 指向字符的32位指针 string HPARAM 32位消息参数 int LPCSTR 指向常字符的32位指针 String LPARAM 32位消息参数 int BYTE 字节 byte WPARAM 32位消息参数 int

BOOL=System.Int32

BOOLEAN=System.Int32

BYTE=System.UInt16

CHAR=System.Int16

COLORREF=System.UInt32

DWORD=System.UInt32

DWORD32=System.UInt32

DWORD64=System.UInt64

FLOAT=System.Float

HACCEL=System.IntPtr

HANDLE=System.IntPtr

HBITMAP=System.IntPtr

HBRUSH=System.IntPtr

HCONV=System.IntPtr

HCONVLIST=System.IntPtr

HCURSOR=System.IntPtr

HDC=System.IntPtr

HDDEDATA=https://www.360docs.net/doc/6d6701393.html,/qz.q/System.IntPtr HDESK=System.IntPtr

HDROP=System.IntPtr

HDWP=System.IntPtr

HENHMETAFILE=System.IntPtr

HFILE=System.IntPtr

HFONT=System.IntPtr

HGDIOBJ=System.IntPtr

HGLOBAL=System.IntPtr

HHOOK=System.IntPtr

HICON=System.IntPtr

HIMAGELIST=System.IntPtr

HIMC=System.IntPtr

HINSTANCE=System.IntPtr

HKEY=System.IntPtr

HLOCAL=System.IntPtr

HMENU=System.IntPtr

HMETAFILE=System.IntPtr

HMODULE=System.IntPtr

HMONITOR=System.IntPtr

HPALETTE=System.IntPtr

HPEN=System.IntPtr

HRGN=System.IntPtr

HRSRC=https://www.360docs.net/doc/6d6701393.html,/qz.q/System.IntPtr HSZ=System.IntPtr

HWINSTA=System.IntPtr

HWND=System.IntPtr

INT=System.Int32

INT32=System.Int32

INT64=System.Int64

LONG=System.Int32

LONG32=System.Int32

LONG64=System.Int64

LONGLONG=System.Int64

LPARAM=System.IntPtr

LPBOOL=System.Int16[]

LPBYTE=System.UInt16[]

LPCOLORREF=System.UInt32[] LPCSTR=System.String LPCTSTR=System.String LPCVOID=System.UInt32 LPCWSTR=System.String LPDWORD=System.UInt32[] LPHANDLE=System.UInt32 LPINT=System.Int32[] LPLONG=System.Int32[] LPSTR=System.String LPTSTR=System.String LPVOID=System.UInt32 LPWORD=System.Int32[] LPWSTR=System.String LRESULT=System.IntPtr PBOOL=System.Int16[] PBOOLEAN=System.Int16[] PBYTE=System.UInt16[] PCHAR=System.Char[] PCSTR=System.String PCTSTR=System.String PCWCH=System.UInt32

PCWSTR=System.UInt32

PDWORD=System.Int32[]

PFLOAT=System.Float[]

PHANDLE=System.UInt32

PHKEY=System.UInt32

PINT=System.Int32[]

PLCID=System.UInt32

PLONG=System.Int32[]

PLUID=System.UInt32

PSHORT=System.Int16[]

PSTR=System.String

PTBYTE=System.Char[]

PTCHAR=System.Char[]

PTSTR=System.String

PUCHAR=System.Char[]

PUINT=System.UInt32[] PULONG=System.UInt32[] PUSHORT=System.UInt16[]

PVOID=System.UInt32

PWCHAR=System.Char[]

PWORD=System.Int16[]

PWSTR=System.String

REGSAM=System.UInt32

SC_HANDLE=System.IntPtr

SC_LOCK=System.IntPtr

SHORT=System.Int16

SIZE_T=System.UInt32

SSIZE_=System.UInt32

TBYTE=System.Char

TCHAR=System.Char

UCHAR=System.Byte

UINT=System.UInt32

UINT32=System.UInt32

UINT64=System.UInt64

ULONG=System.UInt32

ULONG32=System.UInt32

ULONG64=System.UInt64

ULONGLONG=System.UInt64

USHORT=System.UInt16

WORD=System.UInt16

C# 与C++ 数据类型对照表收藏

方便起见,我也将《C# 与C++ 数据类型对照表》转载如下:

C++ C#

=====================================

WORD ushort

DWORD uint

UCHAR int/byte 大部分情况都可以使用int代替,而如果需要严格对齐的话则应该用bytebyte

UCHAR* string/IntPtr

unsigned char* [MarshalAs(UnmanagedType.LPArray)]byte[]/?(Intptr)

char* string

LPCTSTR string

LPTSTR [MarshalAs(UnmanagedType.LPTStr)] string

long int

ulong uint

Handle IntPtr

HWND IntPtr

void*(pvoid)IntPtr

int int

int* ref int

*int IntPtr

unsigned int uint

COLORREF uint

API与C#的数据类型对应关系表

API数据类型类型描述C#类型API数据类型类型描述C#类型

WORD 16位无符号整数ushort CHAR 字符char

LONG 32位无符号整数int DWORDLONG 64位长整数long

DWORD 32位无符号整数uint HDC 设备描述表句柄int

HANDLE 句柄,32位整数int HGDIOBJ GDI对象句柄int

UINT 32位无符号整数uint HINSTANCE 实例句柄int

BOOL 32位布尔型整数bool HWM 窗口句柄int

LPSTR 指向字符的32位指针string HPARAM 32位消息参数int

LPCSTR 指向常字符的32位指针String LPARAM 32位消息参数int

BYTE 字节byte WPARAM 32位消息参数int

本文来自CSDN博客,转载请标明出处:https://www.360docs.net/doc/6d6701393.html,/carl2380/archive/2010/01/21/5219793.aspx

4:一个经典的多线程同步问题汇总

一个经典的多线程同步问题 程序描述: 主线程启动10个子线程并将表示子线程序号的变量地址作为参数传递给子线程。子线程接收参数 -> sleep(50) -> 全局变量++ -> sleep(0) -> 输出参数和全局变量。 要求: 1.子线程输出的线程序号不能重复。 2.全局变量的输出必须递增。 下面画了个简单的示意图: 分析下这个问题的考察点,主要考察点有二个: 1.主线程创建子线程并传入一个指向变量地址的指针作参数,由于线程启动须要花费一定的时间,所以在子线程根据这个指针访问并保存数据前,主线程应等待子线程保存完毕后才能改动该参数并启动下一个线程。这涉及到主线程与子线程之间的同步。 2.子线程之间会互斥的改动和输出全局变量。要求全局变量的输出必须递增。这涉及到各子线程间的互斥。 下面列出这个程序的基本框架,可以在此代码基础上进行修改和验证。 //经典线程同步互斥问题 #include #include #include long g_nNum; //全局资源 unsigned int__stdcall Fun(void *pPM); //线程函数 const int THREAD_NUM = 10; //子线程个数 int main() { g_nNum = 0;

HANDLE handle[THREAD_NUM]; int i = 0; while (i < THREAD_NUM) { handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL); i++;//等子线程接收到参数时主线程可能改变了这个i的值} //保证子线程已全部运行结束 WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE); return 0; } unsigned int__stdcall Fun(void *pPM) { //由于创建线程是要一定的开销的,所以新线程并不能第一时间执行到这来int nThreadNum = *(int *)pPM; //子线程获取参数 Sleep(50);//some work should to do g_nNum++; //处理全局资源 Sleep(0);//some work should to do printf("线程编号为%d 全局资源值为%d\n", nThreadNum, g_nNum); return 0; } 运行结果:

指针与引用的区别(非常经典)

c++中,引用和指针的区别 (1)引用总是指向一个对象,没有所谓的null reference .所有当有可能指向一个对象也由可能不指向对象则必须使用指针. 由于C++ 要求reference 总是指向一个对象所以reference要求有初值. String & rs = string1; 由于没有所谓的null reference 所以所以在使用前不需要进行测试其是否有值.,而使用指针则需要测试其的有效性. (2)指针可以被重新赋值而reference则总是指向最初或地的对象. (3)必须使用reference的场合. Operator[] 操作符由于该操作符很特别地必须返回[能够被当做assignment 赋值对象] 的东西,所以需要给他返回一个reference. (4)其实引用在函数的参数中使用很经常. void Get***(const int& a) //这样使用了引用有可以保证不修改被引用的值 { } 引用和指针 ★相同点: 1. 都是地址的概念; 指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。 ★区别: 1. 指针是一个实体,而引用仅是个别名; 2. 引用使用时无需解引用(*),指针需要解引用; 3. 引用只能在定义时被初始化一次,之后不可变;指针可变; 引用“从一而终” ^_^ 4. 引用没有const,指针有const,const 的指针不可变; 5. 引用不能为空,指针可以为空; 6. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小; typeid(T) == typeid(T&) 恒为真,sizeof(T) == sizeof(T&) 恒为真, 但是当引用作为成员时,其占用空间与指针相同(没找到标准的规定)。

C#多线程函数如何传参数和返回值

C#多线程函数如何传参数和返回值 提起多线程,不得不提起委托(delegates)这个概念. 我理解的委托就是具有同样参数和返回值的函数的集合. 比如 public delegate void MyDelegate(int arg); 就是这种形式的函数 void Myfuntion(int i); 的集合. 如何将一个函数加入委托的集合? MyDelegate dele = new MyDelegate(Myfuntion1); 再增加一个 dele += new MyDelegate(Myfuntion2); ... 委托函数 dele 就是具有整数参数和空返回值的函数 Myfuntion1,2的集合. 调用这个委托函数 dele(1); 就是逐个调用 Myfuntion1,2,... 一般线程函数的声明和启动 Thread t = new Thread(new ThreadStart(MyFunction)); t.Start(); 正是调用了没有参数和返回值的委托函数 ThreadStart 其中的参数MyFunction 是这个委托函数中的一员. 很明显这样无法传参数和返回值,那我们该怎么办? 答案就在委托的BeginInvoke() 方法上, BeginInvoke() 也是(异步)启动一个新线程. 例如 MyDelegate dele = new MyDelegate (MyFunction); dele.BeginInvoke(10,"abcd"); void MyFunction(int count, string str); 可以实现参数的传递. 如何收集线程函数的返回值? 与BeginInvoke 对应有个 EndInvoke 方法,而且运行完毕返回 IAsyncResult 类型的返回值.这样我们可以这样收集线程函数的返回值 MyDelegate dele = new MyDelegate (MyFunction); IAsyncResult ref = dele.BeginInvoke(10,"abcd"); ...

Java中传值与传引用的三种情况

java传值与传引用的三种情况大家先看一个例子: public class Example{ String str=new String("good"); char[]ch={'a','b','c'}; public static void main(String args[]){ Example ex=new Example(); ex.change(ex.str,ex.ch); System.out.print(ex.str+" and "); System.out.print(ex.ch); } public void change(String str,char ch[]){ str="test ok"; ch[0]='g'; } } 看看输出结果? good and gbc java中没有了c++中这样的引用符号,也没像c#中那样提供了out与ref 那么它是怎么做的呢 做什么事情都要去除例外的东西,String类就是此类问题的一个特殊情况 为什么特殊呢?

因为它是一个引用类型,确执行的是值传递。这样说有些抽象,还是举个例子吧 值传递: class Str { public static void main(String[] args) { int i = 900; System.out.println(i); changeInt(i); System.Out.println(i); } public static void changeInt(int s) { s = 34234; } } 结果: 900 900 这就是所谓的值传递。i把自己的副本给了函数changeInt的形参,而在changeInt中虽然将s赋值34234。但是对原来的i值并没有影响,因为它所修改的只是i的copy品而已。

c#中ref和out参数使用时需要注意的问题

c#中ref和out参数使用时需要注意的问题 C#方法中的ref和out {大部分参照<<21天学通C#>>,小部分写了自己的感受,编程功底比较差,只能写这么多,多包涵} ref 通常我们向方法中传递的是值.方法获得的是这些值的一个拷贝,然后使用这些拷贝,当方法运行完毕后,这些拷贝将被丢弃,而原来的值不将受到影响.此外我们还有其他向方法传递参数的形式,引用(ref)和输出(out). 有时,我们需要改变原来变量中的值,这时,我们可以向方法传递变量的引用,而不是变量的值.引用是一个变量,他可以访问原来变量的值,修改引用将修改原来变量的值.变量的值存储在内存中,可以创建一个引用,他指向变量在内存中的位置.当引用被修改时,修改的是内存中的值,因此变量的值可以将被修改.当我们调用一个含有引用参数的方法时,方法中的参数将指向被传递给方法的相应变量,因此,我们会明白,为什么当修改参数变量的修改也将导致原来变量的值. 创建参数按引用传递的方法,需使用关键字ref.例; using System; class gump { public double square(ref double x) { x=x*x; return x; } } class TestApp { public static void Main() { gump doit=new gump(); double a=3; double b=0; Console.WriteLine("Before square->a={0},b={1}",a,b); b=doit.square(ref a); Console.WriteLine("After square->a={0},b={1}",a,b);

基于多线程的制造数据分析和可视化

2007年第24卷第10期微电子学与计算机105 4实例 焊膏印刷是SMT生产过程中的主要工序之一.下面以实现焊膏印刷的焊膏印刷机为例.对上述的原理和过程进行验证。 焊膏印刷机是通过在印刷设备的PC机中插入符合开放标准GEM/SECSlI(通用设备模型)的主机通信卡来实现关键信息的采集。所采集的数据类型包括:前刮刀压力、前刮刀印刷速度、后刮刀压力、后刮刀印刷速度、刮刀正行程位置、刮刀负行程位置、温度值、湿度值等。 该系统首先进入用户登录界面:根据用户的不同权限等级.给与不同的操作许可。选择不同的设备、订单名称、工艺文件名称,开始生产后,焊膏印刷机能方便的实时显示界面。选择想要绘制盖—霄控制图的数据类型.即可绘制出该数据类型的盖—月控制图。如图4所示。 图4-_一R控制图显示界面 5结束语 由于采用了多线程、数据动态实时显示、多媒体定时器、夏—R控制图等技术,使程序实现了对多设备大数据量的实时数据采集、存储、绘制曲线,及时判断数据是否处于失控状态.缩短了延时时间。制造数据可视化程度达95%以上为车间的操作人员提供了随时了解设备运行情况的有效手段.在现实应用中具有广泛的实用价值。 当然.程序也存在一些不足。程序运行在WindowsXP操作系统下.多任务操作系统固有的任务切换:其他驱动程序的CPU时间的抢占;高优先级应用程序的执行:不确定的操作系统的作业任务分配规则等许多问题.都可以导致多媒体定时器定时的不准确。所以,要提高精度.可以考虑采用专门的硬件电路。通过软硬件相结合,以达到高精度的定时,提高应用程序的实用性。 参考文献: 【1】帅梅,王爱周,王广毙.基于Windows数控系统得多线程实现叨.机床与液压.2003 【2】吴丽娜.高槛阳.Wmdows2000/XP下通用实时采集的设计与实现Ⅱ1.计算机应用,2005 【3】肖建明,张向利.一种改进的时间片轮转调度算法田.计算机应用.2005 『41杨乐,王厚军,戴志坚.测试仪器中的动态波形绘制技术叨.仪器仪表学报,2006 『51曹祁,杜树旺.基于微机的压缩机数据采集方法研究与实现U1.仪器仪表学报.2006 【6】杨桂元.中心极限定理及其在统计分析中的应用【J】.管理工程学报.1998 作者简介: 王小婷女.(1969一)。研究方向为计算机工程与应用。 韩方女.研究生。研究方向为图形图像处理、制造过程仿真与优化。 (上接第101页) 网络系统中节点之间的相互作用导致了系统在宏观上表现出了复杂的整体行为.这些结果与已有的研究结果是相一致的日。 4结束语 文中建立了用于分析网络流量行为的一维元胞自动机模型.以节点发送数据分组的规则来描述在传输数据分组过程中节点间的相互影响以及自组织作用后使计算机网络分组传输系统表示出来的一种整体行为.模拟了网络系统发送数据分组随机的不确定状态。仿真结果说明该模型能较好地描述网络流量非拥塞相到拥塞相的变化过程。参考文献: 【1]WolframS.Cellularautomataandcomple6xity[M].RendingMA,Addison-Wesley,1994 【2】彭麟,谭惠丽,孔令江,等.开放性边界条件下双道元胞自动机变通流模型耦合效应研究Ⅱ].物理学报,2003,52(12):3007-3013 p]Ohira T,sa砌嘶凡PhasetransitioninEeom!tⅫltertlet?worktmmemodd田.P}-y8.Rev,1998:193-195 作者简介: 雷霆男.(1972-).博士研究生。讲师。研究方向为通信与信息系统、计算机网络。 余镇危 男.(1942一),教授。研究方向为计算机网络。

String是类似值传递、String数组是引用传递

首先、我们必须牢记的一点是:java语言规范规定,String型变量指向的内存空间中的内容是不能被改变的,即String是不可改变的类! 示例一: public class TestConstant{ public static void main(String args[]){ String str=new String("hello"); str="Welcome to Here"; System.out.println(str); } } 解析:毋庸置疑,此程序输出的将是“Welcome to Here”,但是给str重新赋值的操作(str="Welcome to Here"),不是简单的将str指向的原内存地址内容改为"Welcome to Here",而是从新分配一块内存用来存放"Welcome to Here",然后将str指向该新分配的内存地址。而原来的"hello"如果没有其他String变量指向它,那么他将被java的垃圾收集器回收;如果有其他的String变量指向它,它将在内存继续存在,比如: 示例二: public class TestConstant{ public static void main(String args[]){ String str=new String("hello"); String str1=str; str="123"; System.out.println(str); System.out.println(str1); } }

解析:上面的程序会先后输出123和hello,由于str1仍然指向hello,所以hello所在内存没有被回收。 一、普通的类对象作为函数参数是引用传递 示例三: class Common{ private int a; public Common(int a){ this.a=a; } public void setA(int a){ this.a=a; } public void disp(){ System.out.println(a); } } public class TestCommon{ public static void main(String args[]){ Common c=new Common(1); set(c,3); c.disp(); }

Winform多窗口或多线程传递数据的方法

前提:假设现在有两个窗口Form1和Form2, Form2是Form1的子窗口,现在需要通过Form2来改变Form1中的内容 效果: 方法一:使用Delegate(代理) 第一步:在Form2中定义代理并声明实例 第二步:在Form1中定义用来代理的函数 第三步:在Form1中生成Form2的实例并将代理赋值给Form2中的代理对象

第四步:在Form2中调用代理 总结:当Form2调用代理对象proEvent时实际上是在调用Form1中的Eventpro函数,由于Eventpro属于Form1,所以赋值成功。 方法二:使用自定义事件 第一步:自定义事件 第二步:在Form2中声明事件对象 第三步:在Form1中定义事件回调函数

第四步:创建Form2的对象实例,并将事件的回调函数添加到事件上(订阅事件) 第五步:在Form2中的按钮上触发事件 总结:当第五步事件被触发,事件对象Events会向所有订阅该事件的函数进行触发,而回调函数EventCallBack是Form1的成员,见第三步,所以数据传递成功。 利弊分析:第一种方法的优点显而易见,代理参数是可以自定义的,如:void EventPro(string Message),其缺点就是,每一个这样的跨窗口调用都需要在子窗口中定义一个代理对象,并在主窗口中赋值相应的函数。相对来说,我偏向于使用自定义事件,首先,不是所有学过winform的人都接触过这部分内容(高端大气上档次),其次,他可以实现一个函数向n个窗口传值,只要给事件添加订阅就可以了,frm.Events += new EventHandler(EventCallBack)。(方便)。另外,看过winform下层代

11线程池的使用

第11章线程池的使用 第8章讲述了如何使用让线程保持用户方式的机制来实现线程同步的方法。用户方式的同步机制的出色之处在于它的同步速度很快。如果关心线程的运行速度,那么应该了解一下用户方式的同步机制是否适用。 到目前为止,已经知道创建多线程应用程序是非常困难的。需要会面临两个大问题。一个是要对线程的创建和撤消进行管理,另一个是要对线程对资源的访问实施同步。为了对资源访问实施同步,Wi n d o w s提供了许多基本要素来帮助进行操作,如事件、信标、互斥对象和关键代码段等。这些基本要素的使用都非常方便。为了使操作变得更加方便,唯一的方法是让系统能够自动保护共享资源。不幸的是,在Wi n d o w s提供一种让人满意的保护方法之前,我们已经有了一种这样的方法。 在如何对线程的创建和撤消进行管理的问题上,人人都有自己的好主意。近年来,我自己创建了若干不同的线程池实现代码,每个实现代码都进行了很好的调整,以便适应特定环境的需要。M i c r o s o f t公司的Windows 2000提供了一些新的线程池函数,使得线程的创建、撤消和基本管理变得更加容易。这个新的通用线程池并不完全适合每一种环境,但是它常常可以适合你的需要,并且能够节省大量的程序开发时间。 新的线程池函数使你能够执行下列操作: ? 异步调用函数。 ? 按照规定的时间间隔调用函数。 ? 当单个内核对象变为已通知状态时调用函数。 ? 当异步I / O请求完成时调用函数。 为了完成这些操作,线程池由4个独立的部分组成。表11 - 1显示了这些组件并描述了控制其行为特性的规则。 表11-1 线程池的组件及其行为特性

引用传递的用法

引用是C++引入的新语言特性,是C++常用的一个重要内容之一,正确、灵活地使用引用,可以使程序简洁、高效。 引用简介 引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。 引用的声明方法:类型标识符&引用名=目标变量名; 【例1】:int a; int &ra=a; //定义引用ra,它是变量a 的引用,即别名 说明: (1)&在此不是求地址运算,而是起标识作用。 (2)类型标识符是指目标变量的类型。 (3)声明引用时,必须同时对其进行初始化。 (4)引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,且不能再把该引用名作为其他变量名的别名。 ra=1; 等价于a=1; (5)声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引

用分配存储单元。故:对引用求地址,就是对目标变量求地址。&ra与&a相等。 (6)不能建立数组的引用。因为数组是一个由若干个元素所组成的集合,所以无法建立一个数组的别名。引用应用 1、引用作为参数 引用的一个重要作用就是作为函数的参数。以前的C语言中函数参数传递是值传递,如果有大块数据作为参数传递的时候,采用的方案往往是指针,因为这样可以避免将整块数据全部压栈,可以提高程序的效率。但是现在(C++中)又增加了一种同样有效率的选择(在某些特殊情况下又是必须的选择),就是引用。 【例2】: void swap(int &p1, int &p2) //此处函数的形参p1, p2都是引用 { int p; p=p1; p1=p2; p2=p; } 为在程序中调用该函数,则相应的主调函数的调用

并发危险:解决多线程代码中的 11 个常见的问题

并发危险:解决多线程代码中的11 个常见的问题 并发危险 解决多线程代码中的11 个常见的问题 Joe Duffy 目录 数据争用忘记同步粒度错误读写撕裂无锁定重新排序重新进入死锁锁保护戳记两步舞曲优先级反转实现安全性的模式不变性纯度隔离并发现象无处不在。服 务器端程序长久以来都必须负责处理基本并发编程模型,而随着多核处理器的日益普及,客户端程序也将需要执行一些任务。随着并发操作的不断增加,有关确保安 全的问题也浮现出来。也就是说,在面对大量逻辑并发操作和不断变化的物理硬件并行性程度时,程序必须继续保持同样级别的稳定性和可靠性。 与对应的顺序代码相比,正确设计的并发代码还必须遵循一些额外的规则。对内存的读写以及对共享资源的访问必须使用同步机制进行管制,以防发生冲突。另外,通常有必要对线程进行协调以协同完成某项工作。

这些附加要求所产生的直接结果是,可以从根本上确保线程始终保持一致并且保证其顺利向前推进。同步和协调对时间的依赖性很强,这就导致了它们具有不确定性,难于进行预测和测试。 这 些属性之所以让人觉得有些困难,只是因为人们的思路还未转变过来。没有可供学习的专门 API,也没有可进行复制和粘贴的代码段。实际上的确有一组基础概念需要您学习和适应。很可能随着时间的推移某些语言和库会隐藏一些概念,但如果您现在就 开始执行并发操作,则不会遇到这种情况。本文将介绍需要注意的一些较为常见的挑战,并针对您在软件中如何运用它们给出一些建议。 首先我将讨论在并发程序中经常会出错的一类问题。我把它们称为“安全隐患”,因为它们很容易发现并且后果通常比较严重。这些危险会导致您的程序因崩溃或内存问题而中断。当 从多个线程并发访问数据时会发生数据争用(或竞争条件)。特别是,在一个或多个线程写入一段数据的同时,如果有一个或多个线程也在读取这段数据,则会发生 这种情况。之所以会出现这种问题,是因为Windows 程序(如C++ 和Microsoft .NET Framework

多线程高效访问共享资源

多线程高效访问共享资源 -------BY 懒牛 一、多线程访问共享资源需注意的问题: 1、多个线程如果在一个进程内,可共享进程内的资源。 2、多个线程在不同的进程内,不同进程的资源不能直接共享,要用到内存映射文件。 3、访问方式是用户方式还是内核方式,用户方式速度快,内核方式速度慢。 二、用户方式和内核方式的区别: 1、书上说的用户方式有互锁函数,CRITICAL_SECTION关键代码段,内核方式有信标、事件、互斥量。但是关键代码段也不是完全的用户方式,当一个线程进入关键代码段访问资源,另一个线程是进入内核方式等待的。也是很费时间。经过理解,我认为:用户方式是指当一个线程占有资源时,另外的线程是以什么方式在等待。 2、平常让程序等待的方式有三种,一种是让程序不断的条件循环,当条件达到时,退出。这是最标准的用户方式,依靠循环浪费时间来等待,没用到内核。第二种用sleep()函数,这个不太好用条件控制,本质上也是内核方式。第三种就是内核的Waitfor…..之类的等待函数了。 3、从浪费时间的程度上来看,要分CPU是单核还是多核的,如果是单核的,用户方式的条件循环最浪费时间,因为单核时循环要不断的在几个线程上下文切换特浪费时间;内核方式其次,所以在单核情况下,我们多线程访问资源,就直接用内核方式就OK了。在多核方式下情况有变化,一个线程在第一个CPU上访问资源时,另一个线程可以使用第二个CPU来在用户方式下做条件循环来判断是否能够访问资源了。多核方式下是真正的并发访问,二个线程同时运行,不用做上下文切换。如果这种访问资源的时间用时很短,比如说:一个线程只是在资源上做一个简单运算就离开,则另一个线程在几个用户循环的判断时间就能够访问资源了,何苦要进入内核方式呢?所以在对共享资源访问时,我们先在用户方式下做几个循环来判断,如果能访问了,OK进行访问,如果循环到一定时间,还是不能访问资源,说明这种资源的访问很费时间,在用户方式下继续做循环不合算了,我们就换成内核方式,让系统去帮我等待去吧,我们不管了,哈哈! 三、多线程访问共享资源总结如下: 1、单核时直接进入内核方式等待,等待成功则访问资源。 2、多核时先在用户方式下做循环不断的询问是否能访问,到达一定循环次数,如果条件满足则访问,如果到循环最大值仍然不能访问,则我们也不浪费时间,直接转内核方式等待。 WINDOWS核心编程中为高效访问共享资源,编制了COptex类,使用这个类建立的对象就是多个线程要访问的共享资源,下面让我们来详细分析一下: 表1-1 成员变量描述

1C#的按值传递和按引用传递

C#的按值传递和按引用传递 C#在调用函数有按值传递和按引用传递两种方法。那么这两者有什么区别呢?下面就来简单介绍一下。 C#中的按值传递与大多数编程语言相同,只要在调用方法(有些语言可能为函数)的参数括号中写入要传入的变量名就好了,当然,传入的变量类型要与该方法的参数类型一致。这样,我们就把变量的值传到进所调用的方法里了。但是,参数按值传递(C#默认)时,传递的是参数的副本,且副本的改变并不影响调用者的原始变量值,也就是说,如果我们在在方法中改变了该参数的值,按值传递的方法并不会改变原变量的值。那么,如果我们想要改变的是原变量的值,那应该怎么做呢?这时,就需要使用到引用传递了。C#为此提供了关键字ref和out。对于ref,我们在传递中只要在参数前面使用ref时就可以将变量传递给方法,被调方法这时修改的就是原变量的值了。而在参数前面加上out,则可以建立输出参数,告诉编译器这个变元是按引用传入被调方法的,这样,该变元在被调方法中发生的改变都会反映到原变元。当然,ref和out也是有区别的,使用ref型参数时,传入的参数必须先初始化,而对out型参数而言,则要在方法内完成初始化,这是因为ref可以把参数的数值传进去,而out参数会在传进去前先将参数清空。下面就让我们来看一下例子。 这里创建了一个ReferenceAndOutParameters类,该类包含了三个方法,如下:

方法SquareRef()将参数refparam的值自乘,由于变元按引用传递,因此将改变调用者的原变元值。 方法SquareOut()先将outparam的值赋为6,再自乘,它也将调用者的原变元值。 方法Square()也将参数自乘,但因为调用的是原变元的副本,所以并不会改变原变元的值。 运行结果如下:

Linux学习之线程体传递参数

在线学习好工作https://www.360docs.net/doc/6d6701393.html,/ Linux学习之线程体传递参数 传递参数的两种方法 线程函数只有一个参数的情况:直接定义一个变量通过应用传给线程函数。例子 #include #include using namespace std; pthread_t thread; void * fn(void *arg) { int i = *(int *)arg; cout<<"i = "<

操作系统以进程为单位分配资源。 线程是执行单位,线程函数有多个参数的情况:这种情况就必须申明一个结构体来包含所有的参数,然后在传入线程函数。 具体请查看代码: Mularg.c #include #include #include #include typedef struct arg_struct ARG ; struct arg_struct { char name[10] ; int age ; float weight ; } ; void * thfn ( void * arg ) { ARG * p = (ARG *) arg ; printf( " name is : %s , age is : % d , weight is : %f \ n " , p->name , p->age , p->weight ) ; return NULL ; } int main(int argc , char *argv [ ] ) { pthread_t tid ;

C++中引用传递和指针传递函数参数的详解

先来分析指针这个东东: 从概念上讲,指针本质上就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变。 上面的图表示了程序运行时变量的值和地址,这时的内存长什么样子呢? 注意指针是一个变量,它当然有内存空间,里面存的就是一个地址,通过这个地址我们就能找到它所指向的对象。

说明:上图中两个字母p和n在最左边,代表什么?后面在介绍程序的编译过程中用到,先卖个官司。如果下面的写的东西你看不懂,没关系,往下看,我不相信你看完最后的编译原理的一点点知识,你仍然不懂! 再来分析引用这个东东: 而引用是一个别名,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量)。 上面的这段话,如果不理解,没关系,往下看。 在C++中,指针和引用经常用于函数的参数传递,然而,指针传递参数和引用传递参数是有本质上的不同的: 指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。(这里是在说实参指针本身的地址值不会变)

说明:红线上面是另一个函数的占空间,该函数可以通过指针的方式修改n的值,或者修改自己的值,让自己指向其他的地址,不再指向n。但是不管怎样,它永远修改不了p的值。因为参数传递的方式是值传递。 注意:什么叫能修改p值?能修改p这个变量标识符对应的内存空间就叫做修改了p的值。 而在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

典型环节及其阶跃响应.

自动控制原理实验 典型环节及其阶跃相应 .1 实验目的 1. 学习构成典型环节的模拟电路,了解电路参数对环节特性的影响。 2. 学习典型环节阶跃响应的测量方法,并学会由阶跃响应曲线计算典型环节的传递函数。 3. 学习用Multisim 、MATLAB 仿真软件对实验内容中的电路进行仿真。 .2 实验原理 典型环节的概念对系统建模、分析和研究很有用,但应强调典型环节的数学模型是对各种物理系统元、部件的机理和特性高度理想化以后的结果,重要的是,在一定条件下, 典型模型的确定能在一定程度上忠实地描述那些元、部件物理过程的本质特征。 1.模拟典型环节是将运算放大器视为满足以下条件的理想放大器: (1) 输入阻抗为∞。流入运算放大器的电流为零,同时输出阻抗为零; (2) 电压增益为∞: (3) 通频带为∞: (4) 输入与输出之间呈线性特性: 2.实际模拟典型环节: (1) 实际运算放大器输出幅值受其电源限制是非线性的,实际运算放大器是有惯性的。 (2) 对比例环节、惯性环节、积分环节、比例积分环节和振荡环节,只要控制了输入量的大小或是输入量施加的时间的长短(对于积分或比例积分环节),不使其输出工作在工作期间内达到饱和值,则非线性因素对上述环节特性的影响可以避免.但对模拟比例微分环节和微分环节的影响则无法避免,其模拟输出只能达到有限的最高饱和值。 (3) 实际运放有惯性,它对所有模拟惯性环节的暂态响应都有影响,但情况又有较大的不同。 3.各典型环节的模拟电路及传递函数 (1) 比例环节的模拟电路如图.1所示,及传递函数为: 1 2)(R R S G -=

.1 比例环节的模拟电路 2. 惯性环节的模拟电路如图.2所示,及传递函数为: 其中1 2R R K = T=R 2 C 图.2 惯性环节的模拟电路 3. 积分环节的模拟电路如图.3所示,其传递函数为: 1 11R /1/)(21212212+-=+-=+-=-=TS K CS R R R CS R CS R Z Z S G

c中通过值和引用传递参数

c#中通过值和引用传递参数 在 C# 中,既可以通过值也可以通过引用传递参数。通过引用传递参数允许函数成员(方法、属性、索引器、运算符和构造函数)更改参数的值,并保持该更改。若要通过引用传递参数,请使用ref或out 关键字。为简单起见,本主题的示例中只使用了 ref 关键字。有关ref和out之间的差异的信息,请参见、使用 ref 和 out 传递数组。 本主题包括下列章节: ?传递值类型参数 ?传递引用类型参数 它还包括以下示例: 示例演示是否使用 ref 或 out 1 通过值传递值类型否 2 通过引用传递值类型是 3 交换值类型(两个整数)是 4 通过值传递引用类型否 5 通过引用传递引用类型是 6 交换引用类型(两个字符串)是 传递值类型参数 值类型变量直接包含其数据,这与引用类型变量不同,后者包含对其数据的引用。因此,向方法传递值类型变量意味着向方法传递变量的一个副本。方法内发生的对参数的更改对该变量中存储的原始数据无任何影响。如果希望所调用的方法更改参数值,必须使用ref或out关键字通过引用传递该参数。为了简单起见,以下示例使用ref。 示例 1:通过值传递值类型 下面的示例演示通过值传递值类型参数。通过值将变量myInt传递给方法SquareIt。方法内发生的任何更改对变量的原始值无任何影响。 // PassingParams1.cs using System; class PassingValByVal { static void SquareIt(int x) // The parameter x is passed by value. // Changes to x will not affect the original value of myInt. { x *= x;

(C#)方法参数关键字:ref、out、params详解

ref(C# 参考) ref关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数的任何更改都将反映在该变量中。若要使用ref参数,则方法定义和调用方法都必须显式使用ref关键字。例如: class RefExample { static void Method(ref int i) { i = 44; } static void Main() { int val = 0; //使用ref val必须先初始化 Method(ref val); // val is now 44 } } 传递到 ref 参数的参数必须最先初始化。这与 out 不同,后者的参数在传递之前不需要显式初始化。 尽管ref和out在运行时的处理方式不同,但在编译时的处理方式相同。因此,如果一个方法采用ref参数,而另一个方法采用out参数,则无法重载这两个方法。例如,从编译的角度来看,以下代码中的两个方法是完全相同的,因此将不会编译以下代码: class CS0663_Example { // Compiler error CS0663: "cannot define overloaded // methods that differ only on ref and out". public void SampleMethod(ref int i) { } public void SampleMethod(out int i) { } } 但是,如果一个方法采用ref或out参数,而另一个方法不采用这两个参数,则可以进行重载,如下例所示: class RefOutOverloadExample { public void SampleMethod(int i) { } public void SampleMethod(ref int i) { } }

C#给线程传递参数有3种方式

C#给线程传递参数有3种方式 从《C#高级编程》了解到给线程传递参数有两种方式,一种方式是使用带ParameterizedThreadStart委托参数的Thread构造函数;另一种方式是创建一个自定义类,把线程的方法定义为实例的方法,这样就可以初始化实例的数据,之后启动线程。 方式一:使用ParameterizedThreadStart委托 如果使用了ParameterizedThreadStart委托,线程的入口必须有一个object类型的参数,且返回类型为void。且看下面的例子: using System;using System.Threading;namespace ThreadWithParameters{ class Program { static void Main(string[] args) { string hello = "hello world"; //这里也可简写成Thread thread = new Thread(ThreadMainWith Parameters); //但是为了让大家知道这里用的是ParameterizedThreadStart委托,就没有简写了 Thread thread = new Thread(new ParameterizedThreadStart(T hreadMainWithParameters)); thread.Start(hello); Console.Read(); } static void ThreadMainWithParameters(object obj) { string str = obj as string; if(!string.IsNullOrEmpty(str)) Console.WriteLine("Running in a thread,received: {0}", str); } } } 这里稍微有点麻烦的就是ThreadMainWithParameters方法里的参数必须是object类型的,我们需要进行类型转换。为什么参数必须是object类型呢,各位看看ParameterizedThreadStart委托的声明就知道了。 public delegate void ParameterizedThreadStart(object obj); //ParameterizedThreadStart委托的声明 方式二:创建自定义类

Action Script 3.0 值传递和引用传递

Action Script 3.0 值传递和引用传递 函数的参数可以是任何数据类型的变量,数据类型可以分为简单数据类型和复杂数据类型。当使用简单数据类型变量作为参数时,传递的是值;当使用复杂数据类型变量作为参数时,传递的是引用。值和引用是简单数据类型和复杂数据类型的最大区别。 对于简单数据类型的参数来说,当调用函数开始时,发生了从实参向形参的值传递。当函数调用结束后,形参并未向实参进行值传递,这种数据传递称为值传递。 例如,创建一个名为myTest()的函数,该函数定义了两个数据类型均为int 型的xParam 和yParam 参数。当使用mValue 和nValue 参数调用函数时,xParam 和yParam 参数将用对int 对象的引用进行初始化,int 对象由mValue 和nValue 表示,代码如下所示。 function myTest(xParam:int,yParam:int):void { xParam++; yParam++; trace(xParam,yParam); } var mValue:int = 3; var nValue:int = 7; trace(mValue,nValue); //输出结果为3和7 myTest(mValue,nValue); //输出结果为4和8 trace(mValue,nValue); //输出结果为3和7 从测试结果可以看出,调用函数时,形参的值开始时是由实参传递来的值3 和7,递增后变为4和8。但形参的值改变后并没有传递给实参,所以调用函数前后实参的值都是3和7。 当调用函数开始时,发生了从实参向形参的数据传递,当调用函数结束时形参也会向实参进行数据传递,这种类型传递称为引用传递或地址传递。 例如,创建一个名为myObj 的对象,该对象具有两个属性:x 和y 。该对象作为参数传递给myTest()函数。因为该对象不是基元类型,所以它不但按引用传递,而且还保持一个引用,代码如下所示。 function myTest(Obj:Object):void { Obj.x+=100; Obj.y+=100; trace(Obj.x,Obj.y); }

C#多线程参数传递

C#多线程参数传递 在多线程或单线程任务中,让线程带传入参数一直是个麻烦的问题,通常有种方法就是以类,对像的变量来传参数,这种方法理解上很简单不过在某些场合使用很麻烦,这里就不介绍了,我们主要介绍一种.NET2.0中新增加的带参数运行线程的方法,示例程序如下: ParameterizedThreadStart ParStart = new ParameterizedThreadStart(ThreadMethod); Thread myThread = new Thread(ParStart); object o = “hello”; myThread.Start(o); ThreadMethod如下: public void ThreadMethod(object ParObject) { //程序代码 } 如果是多参数的话可以以数组或动态列表等方式装相入 object,然后使用时拆箱即可 这样是不是简单多了哈,,, ———————————————————————————– [转]个人认为,还是为线程创建一个单独的类,在类的初始化函数里头为类里头的变量赋值,来达到传入参数比较简单。下面有些方法是有问题的,不过我已经达到了目的就懒得去排错了,哪位朋友看出问题了提醒一下啊。呵呵… 方法一: 在VS2003中,也不能直接访问,参看 一般来说,直接在子线程中对窗体上的控件操作是会出现异常,这是由于子线程和运行窗体的线程是不同的空间,因此想要在子线程来操作窗体上的控件,是不可能简单的通过控件对象名来操作,但不是说不能进行操作,微软提供了Invoke的方法,其作用就是让子线程告诉窗体线程来完成相应的控件操作。 现在用一个用线程控制的进程条来说明,大致的步骤如下: 1.创建Invoke函数,大致如下: /// /// Delegate function be invoked by main thread ///

相关文档
最新文档