文档库 最新最全的文档下载
当前位置:文档库 › CSharp如何调用dll中带指针参数

CSharp如何调用dll中带指针参数

CSharp如何调用dll中带指针参数
CSharp如何调用dll中带指针参数

C#调用C++DLL的方法,不同参数类型的调用方法

1. 参数为基本类型,例如int, float, char等

[C++]

void fun(int value);

void fun(float vaue);

void fun(char ch);

[C#]

[DllImport("xxx.dll")]

public static extern void fun(Int32 value);

[DllImport("xxx.dll")]

public static extern void fun(float value);

[DllImport("xxx.dll")]

public static extern void fun(char ch);

2. 参数为基本类型+ 指针,例如int*, float*, char*等

[C++]

void fun(int* value);

void fun(float* vaue);

void fun(char* ch);

[C#]

[DllImport("xxx.dll")]

public static extern void fun(ref Int32 value);

[DllImport("xxx.dll")]

public static extern void fun(ref float value);

参数为char*,在C#中有几种实现方式

A. public static extern void fun(string ch); //ch内容不会改变

B. public static extern void fun(StringBuilderch); //ch内容会改变

3. 参数为结构体

[C++]

struct point

{

int value; //基本类型

char ch; //基本类型

int number[100]; //数组

char buffer[100]; //字符串数组

};

void fun(point pt);

[C#]

[StructLayout(LayoutKind.Sequential)]

publicstruct point

{

public Int32 value;

public char ch;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)] public Int32[] number;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)] public char[] buffer;

}

[DllImport("xxx.dll")]

public static extern void fun(point pt);

4. 参数为结构体指针

[C++]

void fun(point* pt);

[C#]

[DllImport("xxx.dll")]

public static extern void fun(ref point pt);

5. 参数为结构体,并且结构体还嵌套结构体

[C++]

struct point

{

int value; //基本类型

char ch; //基本类型

int number[100]; //数组

char buffer[100]; //字符串数组

struct point pt; //嵌套结构体

};

void fun(point pt);

[C#]

[StructLayout(LayoutKind.Sequential)]

publicstruct point

{

public Int32 value;

public char ch;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)] public Int32[] number;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)] public char[] buffer;

public point pt;

}

[DllImport("xxx.dll")]

public static extern void fun(point pt);

6. 参数为结构体,并且结构体还嵌套结构体指针或者双指针

[C++]

struct point

{

int value; //基本类型

char ch; //基本类型

int number[100]; //数组

char buffer[100]; //字符串数组

struct point* p1; //嵌套结构体指针

struct point** p2; //嵌套结构体双指针

};

void fun(point pt);

[C#]

[StructLayout(LayoutKind.Sequential)]

publicstruct point

{

public Int32 value;

public char ch;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]

public Int32[] number;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]

public char[] buffer;

public IntPtr p1; //使用IntPtr替代嵌套指针

public IntPtr p2; //使用IntPtr替代嵌套指针

}

[DllImport("xxx.dll")]

public static extern void fun(point pt);

由于嵌套指针的使用比较复杂,需要借助一些手段才能够确保正常调用DLL方法[C#]

class Program

{

[StructLayout(LayoutKind.Sequential)]

publicstruct point

{

public Int32 value;

public char ch;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]

public Int32[] number;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]

public char[] buffer;

public IntPtr p1; //使用IntPtr替代嵌套指针

public IntPtr p2; //使用IntPtr替代嵌套指针

}

[DllImport("xxx.dll")]

public static extern void fun(point pt);

static void Main(string[] args)

{

pointpt = new point();

pt.p1 = Marshal.AllocHGlobal(Marshal.Sizeof(typeof(point)));

pt.p2 = Marshal.AllocHGlobal((Marshal.SizeOf(typeof(point))) * 2);

try

{

pt.value = 1;

//实现给p1赋值

pointptt = new point();

ptt.value = 1;

Marshal.StructureToPtr(ptt, pt.p1, false);

//实现给p2赋值

//由于双指针不能够直接传值,需要用到中间结构的数组指针

IntPtr[] ptr = new IntPtr[2];

ptr[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(point)));

ptr[1] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(point)));

try

{

Marshal.StructureToPtr(ptt, ptr[0], false);

Marshal.Copy(ptr, 0, pt.p2, 2);

fun(pt);

//测试返回的指针值是否正确

ptt = (point)Marshal.PtrToStructure(pt.p1, typeof(point));

Marshal.Copy(pt.p2, ptr, 0, 2);

ptt = (point)Marshal.PtrToStructure(ptr[0], typeof(point));

ptt = (point)Marshal.PtrToStructure(ptr[1], typeof(point));

}

catch(System.Exception e)

{

stringstr = e.Message;

}

finally

{

Marshal.FreeHGlobal(ptr[0]);

Marshal.FreeHGlobal(ptr[1]);

}

}

catch(System.Exception e)

{

stringstr = e.Message;

}

finally

{

Marshal.FreeHGlobal(pt.p1);

Marshal.FreeHGlobal(pt.p2);

}

}

}

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++中引用传递与指针传递区别

C++中引用传递与指针传递区别(进一步整理) 从概念上讲。指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变。 而引用是一个别名,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量)。 在C++中,指针和引用经常用于函数的参数传递,然而,指针传递参数和引用传递参数是有本质上的不同的: 指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。(这里是在说实参指针本身的地址值不会变)而在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。 引用传递和指针传递是不同的,虽然它们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针传递的参数,如果改变被调函数中的指针地址,它将影响不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针,或者指针引用。 为了进一步加深大家对指针和引用的区别,下面我从编译的角度来阐述它们之间的区别: 程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。 最后,总结一下指针和引用的相同点和不同点: ★相同点: ●都是地址的概念; 指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。 ★不同点: ●指针是一个实体,而引用仅是个别名; ●引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;

C++程序设计 第八章 指针和引用

C++程序设计 第8章指针和引用 在程序运行时变量和函数都存放在内存中,通过变量名来访问数据、通过函数名来调用函数都是直接访问方式。还有另一种间接访问方式就是用指针。指针的本质是内存地址。指针往往用于说明函数的形参,使实参能通过指针传递,以提高函数调用的效率。利用指针能动态地使用内存,以提高内存使用效率。指针也能用来表示数据关联,以构成复杂的数据结构。指针是C程序中最常见的类型。引用是C++扩展的新概念,主要用于函数形参和返回类型。本章将详细介绍指针和引用的概念及应用。 8.1 指针及指针变量 指针(pointer)的本质是内存地址。指针变量就是专门存储地址的一种变量。通过指针变量所存储的地址来访问数据是一种间接寻址方式。由于处理器的机器语言能支持间接寻址,所以使用指针可以达到较高的计算性能。 8.1.1 地址的概念 C++编译器对不同对象或变量按其数据类型分配合适大小的存储空间。例如为char或bool型变量分配1个字节(bytes)的存储空间,short分配2字节,int和float分配4个字节,为double型变量分配8个字节的存储空间。当程序执行时,代码和变量都加载到内存中。计算机内存被分成若干个存储单元,存储单元以字节为单位。每个存储单元都有一个固定的编号,这个编号就是内存地址。尽管一个变量可能占用多个字节空间,但都通过第一个字节的地址来访问。存放某个变量的第一个字节的地址就是该数据的首地址。 指针即内存单元的地址,而数据是内存单元中的内容(或值)。 假设在程序中说明了1个int型的变量a,其值为68。系统为变量a分配4字节的存储空间,设首地址为0X0065FDF4。通过地址0X0065FDF4就能找到变量a在内存中的存储单元,从而对变量a进行访问。0X0065FDF4就是变量a的指针。知道一个变量的地址和变量的类型就能对变量进行访问,就如同知道房间号就能找到房间,从而找到房间里的主人。 指针是一种特殊的数据类型。所有类型的变量,无论是基本类型、用户定义类型、还是这些类型的数组,在一次运行时都有确定的地址,因此它们都有指针。对于32位计算机,地址长度就是32位,因此一个指针需要4个字节,与整型int、浮点型float具有相同大小的长度。一个指针不仅有值,而且还要确定其类型,表示它能指向什么类型的数据,决定了通过它要取用多少字节作为该变量的值。

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"); ...

C 引用与指针的比较

C 引用与指针的比较 引用是C 中的概念,初学者容易把引用和指针混淆一起。 一下程序中,n是m的一个引用(reference),m是被引用物(referent)。 int m; int &n = m; n相当于m的别名(绰号),对n的任何操作就是对m的操作。 所以n既不是m的拷贝,也不是指向m的指针,其实n就是m它自己。 引用的规则: (1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。 (2)不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)。 (3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。 以下示例程序中,k被初始化为i的引用。 语句k = j并不能将k修改成为j的引用,只是把k的值改变成为6。 由于k是i的引用,所以i的值也变成了6。 int i = 5; int j = 6; int &k = i; k = j; // k和i的值都变成了6; 引用的主要功能是传递函数的参数和返回值。 C 语言中,函数的参数和返回值的传递方式有三种:值传递、指针传递和引用传递。 以下是"值传递"的示例程序。 由于Func1函数体内的x是外部变量n的一份拷贝,改变x的值不会影响n, 所以n的值仍然是0。 void Func1(int x) { x = x 10; } ... int n = 0; Func1(n); cout << "n = " << n << endl; // n = 0 以下是"指针传递"的示例程序。 由于Func2函数体内的x是指向外部变量n的指针,改变该指针的内容将导致n的值改变,所以n的值成为10。

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

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&) 恒为真, 但是当引用作为成员时,其占用空间与指针相同(没找到标准的规定)。

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

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一),教授。研究方向为计算机网络。

C 指针、引用详解

C++指针、引用详解.txt用快乐去奔跑,用心去倾听,用思维去发展,用努力去奋斗,用目标去衡量,用爱去生活。钱多钱少,常有就好!人老人少,健康就好!家贫家富,和睦就好。指针、引用与指针引用传值详解:(下文定义形式中的p都是标识符名,读者可自行修改) 1.指向常量的指针 可以改变指针指向哪个对象,但是不能改变指向对象的值 定义形式: (const int*) p; (int const*) p; //括号可以省去 测试内容: -------------------- int a = 10; const int b = 2; const int* test_p; test_p = &b; //正确,指向常量的指针可以指向常量 test_p = &a; //正确,这里隐式转换:test_p = (const int *)&a;(如果是从const int* 转换到int或者const int 的话,需要显式转换) *test_p = 3;//错误,不能尝试修改所指的对象的值 a++; cout<<*test_p;//将输出11(上一语句虽然不能用*test_p++来修改所指向的对象a,但是由于a是变量,直接对变量进行修改后,指针值*test_p也就指向a++的值了) //这种方法少用,造成用法不明确性 --------------------- //另加: 如果有 int *p; const int b = 2; p = &b;//错误,b是常量,普通指针不能指向常量,这是C++为了保证常量的只读性(毕竟如果p能指向b,那么根据定义*p的值就可以修改,这与常量不能重定义和修改矛盾) --------------------- 2.指针常量 可以改变指向对象的值,但不能改变指向的对象。 定义形式:

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下层代

指针和引用

指针与引用看上去完全不同(指针用操作符“*”和“->”,引用使用操作符“. ”),但是它们似乎有相同的功能。指针与引用都是让你间接引用其他对象。你如何决定在什么时候使用指针,在什么时候使用引用呢? 首先,要认识到在任何情况下都不能使用指向空值的引用。一个引用必须总是指向某些对象。因此如果你使用一个变量并让它指向一个对象,但是该变量在某些时候也可能不指向任何对象,这时你应该把变量声明为指针,因为这样你可以赋空值给该变量。相反,如果变量肯定指向一个对象,例如你的设计不允许变量为空,这时你就可以把变量声明为引用。 “但是,请等一下”,你怀疑地问,“这样的代码会产生什么样的后果?” char *pc = 0; // 设置指针为空值 char& rc = *pc; // 让引用指向空值 这是非常有害的,毫无疑问。结果将是不确定的(编译器能产生一些输出,导致任何事情都有可能发生)。应该躲开写出这样代码的人,除非他们同意改正错误。如果你担心这样的代码会出现在你的软件里,那么你最好完全避免使用引用,要不然就去让更优秀的程序员去做。我们以后将忽略一个引用指向空值的可能性。 因为引用肯定会指向一个对象,在C++里,引用应被初始化。 string& rs; // 错误,引用必须被初始化 string s("xyzzy"); string& rs = s; // 正确,rs指向s 指针没有这样的限制。 string *ps; // 未初始化的指针 // 合法但危险 不存在指向空值的引用这个事实意味着使用引用的代码效率比使用指针的要高。因为在使用引用之前不需要测试它的合法性。 void printDouble(const double& rd) { cout << rd; // 不需要测试rd,它 } // 肯定指向一个double值 相反,指针则应该总是被测试,防止其为空: void printDouble(const double *pd) { if (pd) { // 检查是否为NULL cout << *pd; } } 指针与引用的另一个重要的不同是指针可以被重新赋值以指向另一个不同的对象。但是引用则总是指向在初始化时被指定的对象,以后不能改变。 string s1("Nancy"); string s2("Clancy"); string& rs = s1; // rs 引用s1 string *ps = &s1; // ps 指向s1 rs = s2; // rs 仍旧引用s1, // 但是s1的值现在是 // "Clancy"

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 线程池的组件及其行为特性

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

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

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

实验9 指针与引用

C++程序设计实验报告 学号姓名系别班级计科专教师实验日期同组成员 一、实验编号及名称:实验9 指针与引用 二、实验目的: 1.要求能够使用指针,能够用指针给函数传递参数; 2.理解指针、数组和字符串之间的紧密联系,能够声明和使用字符串数组; 3.掌握引用的语法,用引用传递函数的方法。 三、实验内容及要求 1.P168 ch8_17字符指针的操作 2. P172 ch8_20把一个字符指针数组传递给函数 3. P179 ch8_24(函数指针用作函数参数)计算以0.10为步长,特定范围内的三角函数之和 4.P187 ch9_3给引用赋新值 5.P164 ch8_13用指针实现两个数据交换 P190 ch9_4用引用实现两个数据交换 6. P190 ch9_5 用引用实现函数返回两个值。 四、实验材料、工具、或软件:VC++6.0 五、实验步骤(或记录) 1. 程序如下: #include int main() { char buffer[10]="ABC"; char *pc; pc="hello"; cout<

2.编写的程序如下: #include void Print(char*[],int); void main() { char* pn[]={"Fred","Barney","Wilma","Betty"}; int num =sizeof(pn)/sizeof(char*); Print(pn,num); } void Print(char* arr[], int len) { for(int i=0; i #include double sigma(double(*func)(double),double dl,double du) { double dt=0.0; for(double d=dl; d

引用和用指针的区别

引用和用指针的区别 在c++函数中,形式参数用引用和用指针都可以起到在被调用函数中改变调用函数的变量的作用。什么时候用引用作参数什么时候用指针作参数呢 void function (int *ptr); void function(int &ref); 没有特定的规定。。学的久了,就会习惯什么时候用指针什么时候用引用了引用与指针有什么区别? 1) 引用必须被初始化,指针不必。 2) 引用初始化以后不能被改变,指针可以改变所指的对象。 2) 不存在指向空值的引用,但是存在指向空值的指针。 C++中尽量用引用。个人觉得所有的引用都可以用指针,但指针比引用容易出错。 引用当然更直观更直接,做参数时,如果在函数内不刻意要用指针的那些副作用(如越界访问,动态定向什么的),引用可以代替指针。 C++ 中一般都用引用就可以了 ... C 中没有引用,就使用指针 .... 举例如下: 1 使用指针传递参数时: void function (int *ptr) { 函数体;} 调用该函数时 main() { int p; function (&p); } 2 使用引用传递参数时: void function(int &ref) { 函数体;} 调用该函数时 main() { int p; function (p); } 由此可见,使用引用比使用指针传递参数函数调用时更简单,引用和指针功能大体相同,但是有空间分配时建议最好使用指针,因为在释放空间时,对指针只需要delete就行了,而引用是不能删除空间的,引用必须指向一个存在的对象。 指针和引用的差别 1. 非空的差别任何情况下都不能使用指向空值的引用.一个引用必须总是指向某个对象. 不存在的指向空值的引用这个事实意味着使用引用的代码效率比使用指针要高. 2. 合法性区别在使用引用之前不需要测试他的合法性.指针必须测试. 3. 可修改区别指针可以被重新赋值给另一个不同的对象.但是引用总是指向在初始化的时候被制定的对象,以后不能改变.但是指定的对象其内容可以改变. 应该使用指针的情况: 可能存在不指向任何对象的可能性需要在不同的时刻指向不同的对象(此时,你能够改变指针的指向) 应该使用引用的情况: 如果总是指向一个对象并且一旦指向一个对象后就不会改变指向,使用此时应使用引用。 要首先好好理解指针和引用的区别 指针与引用看上去完全不同(指针用操作符’*’和’->’,引用使用操作符’.’),但是它们似乎有相同的功能。指针与引用都是让你间接引用其他对象。你如何决定在什么时候使用指针,在什么时候使用引用呢? 首先,要认识到在任何情况下都不能用指向空值的引用。一个引用必须总是指向某些对象。因此如果你使用一个变量并让它指向一个对象,但是该变量在某些时候也可能不指向任何对象,这时你应该把变量声明为指针,因为这样你可以赋空值给该变量。相反,如果变量肯定指向一个对象,例如你的设计不允许变量为空,这时你就可以把变量声明为引用。[Page] “但是,请等一下”,你怀疑地问,“这样的代码会产生什么样的后果?” char *pc = 0; // 设置指针为空值 char& rc = *pc; // 让引用指向空值 这是非常有害的,毫无疑问。结果将是不确定的(编译器能产生一些输出,导致任何事情都有可能发生),应该躲开写出这样代码的人除非他们同意改正错误。如果你担心这样的

多线程高效访问共享资源

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

Linux学习之线程体传递参数

在线学习好工作https://www.wendangku.net/doc/2c11357999.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++函数中,形式参数用引用和用指针都可以起到在被调用函数中改变调用函数的变量的作用。什么时候用引用作参数?什么时候用指针作参数呢void function (int *ptr); void function(int &ref); 没有特定的规定。。学的久了,就会习惯什么时候用指针什么时候用引用了! 引用与指针有什么区别? 1) 引用必须被初始化,指针不必。 2) 引用初始化以后不能被改变,指针可以改变所指的对象。 3) 不存在指向空值的引用,但是存在指向空值的指针。 C++中尽量用引用。个人觉得所有的引用都可以用指针,但指针比引用容易出错。 引用当然更直观更直接,做参数时,如果在函数内不刻意要用指针的那些副作用(如越界访问,动态定向什么的),引用可以代替指针。 C++ 中一般都用引用就可以了 ... C 中没有引用,就使用指针 .... 举例如下: 1 使用指针传递参数时: void function (int *ptr) { 函数体;} 调用该函数时 main() { int p; function (&p); } 2 使用引用传递参数时: void function(int &ref) { 函数体;} 调用该函数时 main() { int p; function (p); } 由此可见,使用引用比使用指针传递参数函数调用时更简单,引用和指针功能大体相同,但是有空间分配时建议最好使用指针,因为在释放空间时, 对指针只需要delete就行了,而引用是不能删除空间的,引用必须指向一个存在的对象。 指针和引用的差别 1. 非空的差别任何情况下都不能使用指向空值的引用.一个引用必须总是指向某个对象. 不存在的指向空值的引用这个事实意味着使用引用的代码效率比使用指针要高. 2. 合法性区别在使用引用之前不需要测试他的合法性.指针必须测试. 3. 可修改区别指针可以被重新赋值给另一个不同的对象.但是引用总是指向在初始化的时候被制定的对象,以后不能改变.但是指定的对象其内容可以改变. 应该使用指针的情况: 可能存在不指向任何对象的可能性需要在不同的时刻指向不同的对象(此时,你能 够改变指针的指向) 应该使用引用的情况: 如果总是指向一个对象并且一旦指向一个对象后就不会改变指向,使用此时应使用 引用。 要首先好好理解指针和引用的区别 指针与引用看上去完全不同(指针用操作符’*’和’->’,引用使用操作符’.’),但是它们似乎有相同的功能。 指针与引用都是让你间接引用其他对象。你如何决定在什么时候使用指针,在什么时候使用引用呢? 首先,要认识到在任何情况下都不能用指向空值的引用。一个引用必须总是指向某些对象。因此如果你使用一个变量并让它指向一个对象, 但是该变量在某些时候也可能不指向任何对象,这时你应该把变量声明为指针,因为这样你可以赋空值给

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委托的声明 方式二:创建自定义类

C语言中指针、数组和引用例子实例

一、指针:内容是指示一个内存地址的变量;类型是指示编译器怎么解释指针内容指向地址中的内容,以及该内存区域有多大; 例子: [cpp] int i = 0; int * pi = &i; printf(“pi = %x \n”, pi); // 打印pi的内容: 0x2000 printf(“*pi= %d \n” , *pi); // 打印pi指向地址中的值: 5 printf(“&pi= %x \n”, &pi); // 打印pi的地址: 0x100 从汇编的角度来看,指针是这样的: int i = 0; 010E139E mov dword ptr [i],0 int * pi = &i; 010E13A5 lea eax,[i] 010E13A8 mov dword ptr [pi],eax 二、数组:是一个单一数据类型对象的集合。其中单个对象没有被命名,通过索引访问。 数组名和指针的区别:数组名的内涵在于其指代实体是一种数据结构,这种数据结构就是数组。数组名的外延在于其可以转换为指向其指代实体的指针,而且是一个指针常量。指向数组的指针则是另外一种变量类型,仅仅意味着数组的存放地址 注意:虽然数组名可以转换为指向其指代实体的指针,但是它只能被看作一个指针常量,不能被修改,如下:天骄无双:https://www.wendangku.net/doc/2c11357999.html, [cpp] int intArray[10]; intArray++; // 错误 “指针和数组等价”说的是什么?索引操作相同,例如:p[2]; a[2]; 三、引用(reference)是一个对象的别名。用对象初始化引用后,对象的名字和引用都指向该对象; 引用是如何实现的?从汇编语言的角度来看,指针和引用是一样的: [cpp] int i = 0; 00E9139E mov dword ptr [i],0 int & ref = i; 00E913A5 lea eax,[i] 00E913A8 mov dword ptr [ref],eax int * pi = &i; 00E913AB lea eax,[i] 00E913AE mov dword ptr [pi],eax 指针和引用的区别(从C++使用角度来看): 不存在空引用 引用要初始化 引用初始化后,不能指向另一个对象 这是由编译阶段保证的。 备注:一个指向非常量的引用不能用字面值或者临时值初始化;但是一个指向常量的引用可以。天骄无双:https://www.wendangku.net/doc/2c11357999.html,

相关文档
相关文档 最新文档