本章讲述如何基于Visual C++设计仿真程序。演示了2个程序:ping程序和pong程序进行相互之间的通信。程序使用HLA的交互类进行通信,Visual C++与GNU C++一样,头文件与DMSO RTI1.3NGv6完全一致,但KY-RTI效率要比其快很多。
7.1需求分析
开发2个程序,一个为ping,一个为pong;前者不使用tick服务,后者使用tick服务。
这两个程序就像2个人打乒乓球一样,1个程序向另一个程序发送1个事件;另一个人收到事件后再给对方发送1个事件;如此循环往复。
7.2项目设计
按照需求,将要开发的两个程序叫做ping-notick和pong-tick。该项目与时间无关,不需要时间管理服务。本项目采用交互类,并借用KY-RTI的bin目录下已有的chat.fed文件来传输交互。该交互类名为chat,有name和sentence两个参数,如下列代码所示。
class chat { //交互类
string name; //参数
string sentence; //参数
}
在本项目中,两个程序的name分别设为“ping”和“pong”;sentence为要传输的字符串,其长度可变,具体的值由用户输入确定。
在本项目中存在一个问题,两个程序总有一个程序先启动,另一个后启动;先启动的程序需要等待另一个程序启动后再协同仿真。本项目让ping-notick先启动,具体方案如图7.1所示。在真实项目中可以采用一个管理成员,各个仿真成员启动后向其发送“启动”交互,当管理成员收到所有仿真成员的交互后就可通知仿真开始。这里只是一个演示项目,使得代码尽可能简单。
在图7.1中,假定每个仿真成员发送2次交互后,仿真结束。在具体的程序代码中,这个数由用户输入。在程序中还使用了信号量的概念,当一个仿真成员的回调线程收到对方发来的交互时,则释放信号量,通知主线程继续。
图7.1所示的整个流程为:
- ping-notick先启动;
- ping-notick主线程等待回调线程释放1个信号量;
- pong-tick启动;
- pong-tick向ping-notick发送1个交互;
- pong-tick主线程等待回调线程释放1个信号量;
- ping-notick的回调线程收到交互,释放1个信号量;通知主线程继续;
- ping-notick主线程向pong-tick发送1个交互;
- ping-notick主线程等待回调线程释放1个信号量;
- pong-tick的回调线程收到交互,释放1个信号量;通知主线程继续;
- pong-tick主线程向ping-notick发送1个交互;
- pong-tick主线程等待回调线程释放1个信号量;
- ping-notick的回调线程收到交互,释放1个信号量;通知主线程继续;
- ping-notick主线程向pong-tick发送1个交互;
- ping-notick已经发送了2个交互,结束仿真;在本项目中休眠一段时间后结束仿真;
- pong-tick的回调线程收到交互,释放1个信号量;通知主线程继续;
- pong-tick等到了2次回调,结束仿真。
在实际的代码中,ping-notick采用了信号量,pong-tick采用了一个全局布尔变量,但基本原理与图7.1一样。
图7.1 每个仿真成员发送2次交互后结束仿真
7.3 ping-notick代码设计
该程序由ping-notick.cpp和HwFederateAmbassador.cpp两个文件组成。前者负责发送交互,后者负责从RTI接收交互,两者在执行时处于2个独立的线程中。
ping-notick.cpp代码说明:
12行:定义变量STEP,用来表示发送多少次交互后仿真结束,初始值为100;
13行:发送1个交互时要传输的字节数;
16-18行:定义交互类及其参数句柄变量;
33-39行:输入要传输的字节数;
41-48行:输入要发送的交互数;
51-55行:创建1个信号量;
65-72行:创建联邦执行;
74-93行:加入联邦执行;
99-104行:获取交互类及其参数句柄;
107行:公布交互类,只有公布之后才能够向RTI发送交互;
109行:订购交互类,只有订购之后才能够从RTI收到其他人的聊天内容;
111-113行:根据要发送的字节数生成字符串;
115-121行:生成要传输的交互信息,将name和sentence打包,后面直接调用sendInteraction发送;
123-132行:循环操作,每次等待回调线程释放1个信号量,收到信号量后发送1个交互;
138-147行:退出联邦执行,不再参加仿真;
156-169行:销毁联邦。如果是最后一个仿真成员执行该操作,则整个仿真结束。
表7.1 Visual C++ ping-notick示例:ping-notick.cpp
- #include "stdafx.h"
- #include "HwFederateAmbassador.hh"
- #include <RTI.hh>
- #include <fedtime.hh>
- #include <windows.h> // for "Sleep"
- #include <iostream>
- using namespace std;
- int STEP=100;
- int data_size=1024 ;
- //定义交互类句柄和参数句柄
- RTI::InteractionClassHandle hChatClass; //对应chat.xml中的chat交互类
- RTI::ParameterHandle hChatName; //对应chat交互类的name参数
- RTI::ParameterHandle hChatSentence; //对应chat交互类的sentence参数
- HANDLE syt;
- int hw_main(int argc, char *argv[])
- {
- char federationExecutionName[50];//联盟名称
- strcpy(federationExecutionName, "chat");
- char FDDfile[50];//FDD文件
- strcpy(FDDfile, "chat.fed");
- char federateType[50];//盟员名称
- strcpy(federateType, "ping");
- cout << endl << "请输入要传输的字节数:" ; //ping和pong要一致
- cin >> data_size;
- if (data_size < 0) {
- cerr << "字节数不正确" << endl;
- exit(1);
- }
- cout << endl << "请输入交互次数:" ; //ping和pong要一致
- cin >> STEP;
- cout << endl;
- if (STEP < 1) {
- cerr << "交互次数不正确" << endl;
- exit(1);
- }
- //syt = CreateSemaphore(NULL, 0, 1, syt_name.c_str()); //no data to read
- syt = CreateSemaphore(NULL, 0, 1, _T("ps")); //no data to read
- if (syt != NULL && GetLastError() == ERROR_ALREADY_EXISTS) {
- printf("Semaphore has been created.\n");
- }
- try {
- RTI::RTIambassador rti; // libRTI provided
- HwFederateAmbassador fedAmb; // User-defined
- RTI::FederateHandle federateId;
- RTI::Boolean Joined = RTI::RTI_FALSE;
- int numTries = 0;
- try {
- rti.createFederationExecution(federationExecutionName, FDDfile);
- } catch ( RTI::FederationExecutionAlreadyExists& e ) {
- cerr << "FED_HW: Note: Federation execution already exists." << e << endl;
- } catch ( RTI::Exception& e ) {
- cerr << "FED_HW: ERROR:" << e << endl;
- return -1;
- }
- try {
- cout << "FED_HW: JOINING FEDERATION EXECUTION: " << endl;
- federateId = rti.joinFederationExecution( federateType,
- federationExecutionName,
- &fedAmb);
- } catch (RTI::FederateAlreadyExecutionMember& e) {
- cerr << "FED_HW: ERROR: " << argv[1]
- << " already exists in the Federation Execution "
- << federationExecutionName << "." << endl;
- cerr << e << endl;
- return -1;
- } catch (RTI::FederationExecutionDoesNotExist&) {
- cerr << "FED_HW: ERROR: Federation Execution "
- << "does not exists."<< endl;
- rti.tick(2.0, 2.0);
- } catch ( RTI::Exception& e ) {
- cerr << "FED_HW: ERROR:" << e << endl;
- return -1;
- }
- cout << "FED_HW: JOINED SUCCESSFULLY: " << ": Federate Handle = " << federateId << endl;
-
- //获取交互类句柄
- hChatClass = rti.getInteractionClassHandle("chat");
- //获取交互类参数句柄
- hChatName = rti.getParameterHandle("name", hChatClass);
- hChatSentence = rti.getParameterHandle("sentence", hChatClass);
- //公布交互类,这样可以向RTI发送信息
- rti.publishInteractionClass(hChatClass);
- //定购交互类,这样可以接受来自其它发布者的信息
- rti.subscribeInteractionClass(hChatClass);
- string szSentence;
- szSentence.resize(data_size);
- szSentence.assign(data_size, 'a');
- RTI::ParameterHandleValuePairSet* pParams = NULL;
- long numParams(2);
- pParams = RTI::ParameterSetFactory::create (numParams);
- // Add Name
- pParams->add(hChatName,(char*)federateType, strlen(federateType)+1);
- pParams->add(hChatSentence,(char*)szSentence.c_str(), data_size);
- for(int i=0; i<STEP; i++) {
- WaitForSingleObject(syt, INFINITE); //ping先启动,i=0时在这里等待pong启动后向其发送1个交互
- //发送交互,所有定购者(不包括自己)都会在HwFederateAmbassador.cpp中的receiveInteraction服务中收到该交互。
- try {
- rti.sendInteraction(hChatClass, *pParams, "");
- } catch(...) {
- cerr << "error for send interaction" << endl;
- }
- }
- pParams->empty();
- delete pParams; // Deallocate the memory
- Sleep(3000); //3 seconds
- try {
- cout << "FED_HW: RESIGN FEDERATION EXECUTION CALLED" << endl;
- rti.resignFederationExecution(
- RTI::DELETE_OBJECTS_AND_RELEASE_ATTRIBUTES );
- cout << "FED_HW: SUCCESSFUL RESIGN FEDERATION EXECUTION CALLED" << endl;
- } catch ( RTI::Exception& e ) {
- cerr << "FED_HW: ERROR:" << e << endl;
- return -1;
- }
- //------------------------------------------------------
- // Destroy the federation execution in case we are the
- // last federate. This will not do anything bad if there
- // other federates joined. The RTI will throw us an
- // exception telling us that other federates are joined
- // and we can just ignore that.
- //------------------------------------------------------
- try {
- cout << "FED_HW: DESTROY FEDERATION EXECUTION CALLED" << endl;
- rti.destroyFederationExecution( federationExecutionName );
- cout << "FED_HW: SUCCESSFUL DESTROY FEDERATION EXECUTION CALLED" << endl;
- } catch ( RTI::FederatesCurrentlyJoined& /* e */ ) {
- cerr << "FED_HW: FederatesCurrentlyJoined" << endl;
- return 0;
- } catch ( RTI::FederationExecutionDoesNotExist& /* e */) {
- cerr << "FED_HW: FederationExecutionDoesNotExist" << endl;
- return 0;
- } catch ( RTI::Exception& e ) {
- cerr << "FED_HW: ERROR:" << e << endl;
- return -1;
- }
- } catch (RTI::ConcurrentAccessAttempted& e) {
- cerr << e << endl;
- return -1;
- } catch ( RTI::Exception& e ) {
- cerr << "FED_HW: ERROR:" << e << endl;
- return -1;
- }
- cout << "FED_HW: Exiting ." << endl;
- return 0;
- }
- int
- main(int argc, char** argv)
- {
- return hw_main(argc, argv);
- }
|
HwFederateAmbassador.cpp代码说明:
32-45行:由于不处理时间参数,因此如果接收到这种类型的receiveInteraction交互,则直接调用不带时间参数的服务来统一处理;
47-58行:接收到交互后,释放信号量。
表7.2 Visual C++ ping-notick示例:HwFederateAmbassador.cpp
- //-----------------------------------------------------------------
- // Project Include Files
- //-----------------------------------------------------------------
- #include "fedtime.hh"
- #include "HwFederateAmbassador.hh"
- //-----------------------------------------------------------------
- // System Include Files
- //-----------------------------------------------------------------
- #ifndef _MSC_VER
- #include <stdio.h>
- #include <stdlib.h>
- #include <iostream.h>
- #else
- #include <iostream>
- using std::cout;
- using std::cerr;
- using std::endl;
- #endif
- #include <windows.h>
- //-----------------------------------------------------------------
- // Bad C like global variables being externed - bad boy!!!
- //-----------------------------------------------------------------
- extern HANDLE syt;
- extern RTI::InteractionClassHandle hChatClass;
- extern RTI::ParameterHandle hChatName;
- extern RTI::ParameterHandle hChatSentence;
- void HwFederateAmbassador::receiveInteraction (
- RTI::InteractionClassHandle theInteraction, // supplied C1
- const RTI::ParameterHandleValuePairSet& theParameters, // supplied C4
- const RTI::FedTime& theTime, // supplied C4
- const char *theTag, // supplied C4
- RTI::EventRetractionHandle theHandle) // supplied C1
- throw (
- RTI::InteractionClassNotKnown,
- RTI::InteractionParameterNotKnown,
- RTI::InvalidFederationTime,
- RTI::FederateInternalError)
- {
- this->receiveInteraction( theInteraction, theParameters, theTag );
- }
- void HwFederateAmbassador::receiveInteraction (
- RTI::InteractionClassHandle theInteraction, // supplied C1
- const RTI::ParameterHandleValuePairSet& theParameters, // supplied C4
- const char *theTag) // supplied C4
- throw (
- RTI::InteractionClassNotKnown,
- RTI::InteractionParameterNotKnown,
- RTI::FederateInternalError)
- {
- cout << "received an interaction from pong" << endl;
- ReleaseSemaphore(syt,1,NULL);
- }
|
7.4 pong-tick代码设计
pong-tick.cpp代码说明:
13行:定义变量STEP,用来表示发送多少次交互后仿真结束,初始值为100;
14行:发送1个交互时要传输的字节数;
17-19行:定义交互类及其参数句柄变量;
34-40行:输入要传输的字节数;
42-49行:输入要发送的交互数;
59-66行:创建联邦执行;
68-87行:加入联邦执行;
92-96行:获取交互类及其参数句柄;
99行:公布交互类,只有公布之后才能够向RTI发送交互;
101行:订购交互类,只有订购之后才能够从RTI收到其他人的聊天内容;
103-105行:根据要发送的字节数生成字符串;
107-113行:生成要传输的交互信息,将name和sentence打包,后面直接调用sendInteraction发送;
115-127行:循环操作,每次发送1个交互后等待回调线程通知收到交互;124行调用tick获取回调;
134-143行:退出联邦执行,不再参加仿真;
152-165行:销毁联邦。如果是最后一个仿真成员执行该操作,则整个仿真结束。
表7.3 Visual C++ pong示例:pong-tick.cpp
- #include "stdafx.h"
- #include "HwFederateAmbassador.hh"
- #include <RTI.hh>
- #include <fedtime.hh>
- # include <windows.h> // for "Sleep"
- # include <sys/timeb.h> // for "struct _timeb"
- # include <iostream>
- using namespace std;
- int STEP=100;
- int data_size=1024;
- //定义交互类句柄和参数句柄
- RTI::InteractionClassHandle hChatClass; //对应chat.xml中的chat交互类
- RTI::ParameterHandle hChatName; //对应chat交互类的name参数
- RTI::ParameterHandle hChatSentence; //对应chat交互类的sentence参数
- bool svt = false;
- int hw_main(int argc, char *argv[])
- {
- char federationExecutionName[50];//联盟名称
- strcpy(federationExecutionName, "chat");
- char FDDfile[50];//FDD文件
- strcpy(FDDfile, "chat.fed");
- char federateType[50];//盟员名称
- strcpy(federateType, "pong");
- cout << endl << "请输入要传输的字节数:" ; //与ping要一致
- cin >> data_size;
- if (data_size < 0) {
- cerr << "字节数不正确" << endl;
- exit(1);
- }
- cout << endl << "请输入交互次数:" ; //与ping要一致
- cin >> STEP;
- cout << endl;
- if (STEP < 1) {
- cerr << "交互次数不正确" << endl;
- exit(1);
- }
- try {
- RTI::RTIambassador rti; // libRTI provided
- HwFederateAmbassador fedAmb; // User-defined
- RTI::FederateHandle federateId;
- RTI::Boolean Joined = RTI::RTI_FALSE;
- int numTries = 0;
- try {
- rti.createFederationExecution(federationExecutionName, FDDfile);
- } catch ( RTI::FederationExecutionAlreadyExists& e ) {
- cerr << "FED_HW: Note: Federation execution already exists." << e << endl;
- } catch ( RTI::Exception& e ) {
- cerr << "FED_HW: ERROR:" << e << endl;
- return -1;
- }
- try {
- cout << "FED_HW: JOINING FEDERATION EXECUTION: " << endl;
- federateId = rti.joinFederationExecution( federateType,
- federationExecutionName,
- &fedAmb);
- } catch (RTI::FederateAlreadyExecutionMember& e) {
- cerr << "FED_HW: ERROR: " << argv[1]
- << " already exists in the Federation Execution "
- << federationExecutionName << "." << endl;
- cerr << e << endl;
- return -1;
- } catch (RTI::FederationExecutionDoesNotExist&) {
- cerr << "FED_HW: ERROR: Federation Execution "
- << "does not exists."<< endl;
- rti.tick(2.0, 2.0);
- } catch ( RTI::Exception& e ) {
- cerr << "FED_HW: ERROR:" << e << endl;
- return -1;
- }
- /
- //获取交互类句柄
- hChatClass = rti.getInteractionClassHandle("chat");
- //获取交互类参数句柄
- hChatName = rti.getParameterHandle("name", hChatClass);
- hChatSentence = rti.getParameterHandle("sentence", hChatClass);
- //公布交互类,这样可以向RTI发送信息
- rti.publishInteractionClass(hChatClass);
- //定购交互类,这样可以接受来自其它发布者的信息
- rti.subscribeInteractionClass(hChatClass);
- string szSentence;
- szSentence.resize(data_size);
- szSentence.assign(data_size, 'a');
- RTI::ParameterHandleValuePairSet* pParams = NULL;
- long numParams(2);
- pParams = RTI::ParameterSetFactory::create (numParams);
- // Add Name
- pParams->add(hChatName,(char*)federateType, strlen(federateType)+1);
- pParams->add(hChatSentence,(char*)szSentence.c_str(), data_size);
- for(int i=0; i<STEP; i++) {
- //发送交互,所有定购者(不包括自己)都会在HwFederateAmbassador.cpp中的receiveInteraction服务中收到该交互。
- try {
- rti.sendInteraction(hChatClass, *pParams, "");
- } catch(...) {
- cerr << "error for send interaction" << endl;
- }
- while(!svt) { //等待ping发交互
- rti.tick(0.001, 1.0);
- }
- svt = false;
- }
- pParams->empty();
- delete pParams; // Deallocate the memory
- Sleep(3000); //3 seconds
- try {
- cout << "FED_HW: RESIGN FEDERATION EXECUTION CALLED" << endl;
- rti.resignFederationExecution(
- RTI::DELETE_OBJECTS_AND_RELEASE_ATTRIBUTES );
- cout << "FED_HW: SUCCESSFUL RESIGN FEDERATION EXECUTION CALLED" << endl;
- } catch ( RTI::Exception& e ) {
- cerr << "FED_HW: ERROR:" << e << endl;
- return -1;
- }
- //------------------------------------------------------
- // Destroy the federation execution in case we are the
- // last federate. This will not do anything bad if there
- // other federates joined. The RTI will throw us an
- // exception telling us that other federates are joined
- // and we can just ignore that.
- //------------------------------------------------------
- try {
- cout << "FED_HW: DESTROY FEDERATION EXECUTION CALLED" << endl;
- rti.destroyFederationExecution( federationExecutionName );
- cout << "FED_HW: SUCCESSFUL DESTROY FEDERATION EXECUTION CALLED" << endl;
- } catch ( RTI::FederatesCurrentlyJoined& /* e */ ) {
- cerr << "FED_HW: FederatesCurrentlyJoined" << endl;
- return 0;
- } catch ( RTI::FederationExecutionDoesNotExist& /* e */) {
- cerr << "FED_HW: FederationExecutionDoesNotExist" << endl;
- return 0;
- } catch ( RTI::Exception& e ) {
- cerr << "FED_HW: ERROR:" << e << endl;
- return -1;
- }
- } catch (RTI::ConcurrentAccessAttempted& e) {
- cerr << e << endl;
- return -1;
- } catch ( RTI::Exception& e ) {
- cerr << "FED_HW: ERROR:" << e << endl;
- return -1;
- }
- cout << "FED_HW: Exiting ." << endl;
- return 0;
- }
- int
- main(int argc, char** argv)
- {
- return hw_main(argc, argv);
- }
|
HwFederateAmbassador.cpp代码说明:
33-46行:由于不处理时间参数,因此如果接收到这种类型的receiveInteraction交互,则直接调用不带时间参数的服务来统一处理;
48-59行:接收到交互后,通过全局布尔变量通知主线程继续。
表7.4 Visual C++ pong示例:HwFederateAmbassador.cpp
- //-----------------------------------------------------------------
- // Project Include Files
- //-----------------------------------------------------------------
- #include "fedtime.hh"
- #include "HwFederateAmbassador.hh"
- //-----------------------------------------------------------------
- // System Include Files
- //-----------------------------------------------------------------
- #ifndef _MSC_VER
- #include <stdio.h>
- #include <stdlib.h>
- #include <iostream.h>
- #else
- #include <iostream>
- using std::cout;
- using std::cerr;
- using std::endl;
- #endif
- #include <windows.h>
- //-----------------------------------------------------------------
- // Bad C like global variables being externed - bad boy!!!
- //-----------------------------------------------------------------
- extern bool svt;
- extern RTI::InteractionClassHandle hChatClass;
- extern RTI::ParameterHandle hChatName;
- extern RTI::ParameterHandle hChatSentence;
- void HwFederateAmbassador::receiveInteraction (
- RTI::InteractionClassHandle theInteraction, // supplied C1
- const RTI::ParameterHandleValuePairSet& theParameters, // supplied C4
- const RTI::FedTime& theTime, // supplied C4
- const char *theTag, // supplied C4
- RTI::EventRetractionHandle theHandle) // supplied C1
- throw (
- RTI::InteractionClassNotKnown,
- RTI::InteractionParameterNotKnown,
- RTI::InvalidFederationTime,
- RTI::FederateInternalError)
- {
- this->receiveInteraction( theInteraction, theParameters, theTag );
- }
- void HwFederateAmbassador::receiveInteraction (
- RTI::InteractionClassHandle theInteraction, // supplied C1
- const RTI::ParameterHandleValuePairSet& theParameters, // supplied C4
- const char *theTag) // supplied C4
- throw (
- RTI::InteractionClassNotKnown,
- RTI::InteractionParameterNotKnown,
- RTI::FederateInternalError)
- {
- cout << "received an interaction from ping" << endl;
- svt = true;
- }
|
7.5编译运行
下面以Visual C++ 2010为例说明编译运行过程。
第1步:编译。以ping-notick程序为例说明,pong-tick程序的设置与此相同。
(1)选择左侧“ping-notick”根节点,按右键选择“属性”,打开属性对话框;
图7.2 选择项目属性
(2)设置项目属性
- 在“配置”处选择Debug或Release等;
- 在“平台”处选择32位或64位等;
- 选择“C/C++”的“常规”属性,设置KY-RTI的头文件目录,这里设置为“C:\KY-RTI\include;.”。注意,这里有两个目录,一个是KY-RTI的include目录,另一个是当前目录,用‘.’表示,中间用‘;’隔开。
- 选择“链接器”的“常规”属性,设置KY-RTI的库文件目录,这里设置为“C:\KY-RTI\lib”。
- 选择“链接器”的“输入”属性,设置项目需要的库文件,依照VC版本以及平台属性设置需要的库文件,这里设置为VC2010的64位版本库“libFedTime64VC2010.lib;libRTI-NG64VC2010.lib”。
图7.3 设置项目属性
图7.4 设置库文件目录
图7.5 设置库
(3)编译,生成可执行程序。
第2步:修改RTI.rid,查看tick开关。
ping-notick没有使用tick服务,则关闭tick开关;pong-tick使用了tick服务,则打开tick开关。
如果当前目录下没有RTI.rid,则运行程序后会自动产生。
第3步:启动KY-RTI。注意,KY-RTI的IP地址和端口号要与RTI.rid一致。
第4步:开启两个终端,分别运行ping-notick和pong-tick这2个仿真成员,开始仿真。如图7.6和图7.7所示。在这个例子中,每次传输的字节数为100个字节,一共来回10次。
图7.6 ping-notick运行结果
图7.7 pong-tick运行结果
KY-RTI的Linux、Windows版本和源码请联系作者:walt_lbq@163.com
KY-RTI分布仿真技术:前 言
KY-RTI分布仿真技术:第一章 简介
KY-RTI分布仿真技术:第二章 系统安装
KY-RTI分布仿真技术:第三章 KY-OMT对象模型模板工具
KY-RTI分布仿真技术:第四章 C++程序设计
KY-RTI分布仿真技术:第五章 Qt程序设计
KY-RTI分布仿真技术:第六章 Java程序设计
KY-RTI分布仿真技术:第七章 Visual C++程序设计
KY-RTI分布仿真技术:第八章 Visual C#程序设计
KY-RTI分布仿真技术:第九章 综合演示
KY-RTI分布仿真技术:附录1 分组聊天(HLA数据分发管理的应用)
KY-RTI分布仿真技术:附录2 大联邦(构建1000个成员的HLA/RTI仿真系统)
KY-RTI分布仿真技术:附录3 国产化(操作系统+CPUs)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)