我知道至少在这里有人问过这个问题。
但是没有一个令人满意的答案,至少对我来说不是。关于与非托管代码进行互操作方面的封送讨论很多,但是从一个线程到另一个线程进行封送又是怎么回事,就像我们有时在.NET中要做的那样。
这使我问,什么是编组,真的吗?当给出编组的定义时,如何定义它以便解释互操作性的情况以及线程之间“编组”的情况?
Answers:
计算通常需要将数据从一个站点移动到另一个站点,并且没有任何共享内存。因此,一种计算会将包含数据的消息发送给另一种。
如果数据非常复杂,该如何以消息形式发送?
编组是将数据字段或整个相关结构集转换为可在消息中发送的序列化字符串的过程。要编组二进制数字,如果消息格式必须为文本,则可以将其转换为十六进制数字字符串。如果消息将携带二进制数据,则二进制数可能会转换为4个little-endian标准化二进制字节,并以这种方式发送。指针更难。通常必须将它们转换为独立于实际内存位置的抽象引用(例如,“节点号”)。
当然,如果“封送”数据,则最终必须“拆封”,这是读取串行流并重建传输的数据(结构)的过程。
通常,库中有用于完成此目的的(解组)例程,有时甚至有一些工具可以制造(解)组例程中用于发送/接收数据的所有调用。
编组正在获取某种形式的数据,并将其转换为单独的形式。这是一个非常通用的术语,在很多地方使用时,含义上都有细微的差别。
例如,在.NET中,当您使用本机类型时,互操作层将.NET类型中的数据“封送”为适当的形式以调用本机方法,然后“封送”结果。
至于线程之间的“编组”-通常,您需要使代码在不同于当前线程的线程上运行。例如,如果您使用的是Windows Forms,则不能在线程池线程上更改UI元素,因此您需要“封送”对UI线程的调用。这是通过创建一个委托,然后通过Control.Invoke(使用相当复杂的系统将该委托回传到适当的同步上下文)将委托传递回用户界面线程来完成的,该代理又在用户界面上运行委托为您服务。
维基百科的定义实际上是相当不错的。
编组的总体概念与“序列化”相同:从内存中的表示形式(某种程度上,它根本没有表示形式-当内存中的某物只是“存在”时)变为“硬拷贝” ”表示形式,无论是XML还是二进制流之类的东西。但是,根据您的操作,它也可能意味着某种转换或转换为目标格式。
对于进程编组:一个线程不能简单地“调用”另一个线程-数据必须打包并从一个线程“发送”到另一个线程。编组是打包该数据(例如,有关要调用的方法及其参数的数据)的过程。
如果要按照互操作性进行编组,则将方法调用及其参数打包到一个数据结构中,该数据结构可以发送到运行COM组件的进程/线程。该程序包必须采用COM组件可以理解的格式。
编组(类似于序列化)是将对象的内存表示形式转换为适合存储或传输的数据格式的过程。通常在必须在计算机程序的不同部分之间或从一个程序到另一个程序之间移动数据时使用。
在从.NET调用非托管函数的情况下,将使用编组将.NET的数据转换为非托管函数可以使用的数据。例如,System.String
基于Unicode,但是该字符串可能需要转换为ANSI字符串才能传递给非托管C函数。
对于线程,编组通常是指将某些数据的所有权从一个线程转移到另一个线程。例如,一个程序有两个线程。第一个线程从网络读取数据,第二个线程计算该数据。网络线程读取某些数据后,它将数据传输(即“封送”)到计算线程进行处理。它可以通过将数据写入两个线程之间共享的队列中来实现。
线程中的封送处理几乎总是涉及封送数据的同步。
我理解封送处理的方式是,它为您提供了一种在各种操作环境中以一致的方式传输数据的方法。
在将数据从托管代码整理到非托管代码的情况下,它或多或少是相同的。
我有一些数据,例如整数数组或我选择的任何数据类型,我想在我的C ++代码对其执行一些操作后使其在C#代码中可用。
我不能对C#代码说“嘿,这就是数组所在的位置,做您想做的事”。C ++中的整数数组的存储方式可能与C#中的存储方式不同。封送处理让我们以与环境无关的方式传输此数据,以便双方以相同的精确方式查看数据。
另一个例子是在网络中。您通常不称这种封送处理,但如果要通过网络传输,则通常必须以一种方式来传输它,即无论接收到它的人都以与您相同的方式解释数据。您的计算机可以按小端顺序显示数据,另一台计算机可以按大端顺序显示数据。
tl; dr:封送处理为您提供了一种在各种操作环境中一致地表示数据的方法