Windows系统编程之进程间通信

Windows系统编程之进程间通信
作者:北极星2003
来源:看雪论坛(www.pediy.com)
Windows 的IPC(进程间通信)机制主要是异步管道和命名管道。(至于其他的IPC方式,例如内存映射、邮槽等这里就不介绍了)
管道(pipe)是用于进程间通信的共享内存区域。创建管道的进程称为管道服务器,而连接到这个管道的进程称为管道客户端。一个进程向管道写入信息,而另外一个进程从管道读取信息。
异步管道是基于字符和半双工的(即单向),一般用于程序输入输出的重定向;命名管道则强大地多,它们是面向消息和全双工的,同时还允许网络通信,用于创建客户端/服务器系统。
一、异步管道(实现比较简单,直接通过实例来讲解)
实验目标:当前有sample.cpp, sample.exe, sample.in这三个文件,sample.exe为sample.cpp的执行程序,sample.cpp只是一个简单的程序示例(简单求和),如下:

代码:
[cpp] view plain copy
  1. #include <iostream.h>  
  2. int main()  
  3. {  
  4.   int a, b ;  
  5.   while ( cin >> a >> b && ( a || b ) )  
  6.     cout << a + b << endl ;  
  7.   return 0;  
  8. }  
Sample.in文件是输入文件,内容:
32 433
542 657
0 0
要求根据sample.exe和它的输入数据,把输出数据重定向到sample.out
流程分析:实际这个实验中包含两个部分,把输入数据重定向到sample.exe 和把输出数据重定向到sample.out。在命令行下可以很简单的实现这个功能“sample <sample.in >sample.out”,这个命令也是利用管道特性实现的,现在我们就根据异步管道的实现原理自己来实现这个功能。
管道是基于半双工(单向)的,这里有两个重定向的过程,显然需要创建两个管道,下面给出流程图:
异步管道实现的流程图说明:
1)。父进程是我们需要实现的,其中需要创建管道A,管道B,和子进程,整个实现流程分为4个操作。
2)。管道A:输入管道
3)。管道B:输出管道
4)。操作A:把输入文件sample.in的数据写入输入管道(管道A)
5)。操作B:子进程从输入管道中读取数据,作为该进程的加工原料。通常,程序的输入数据由标准的输入设备输入,这里实现输入重定向,即把输入管道作为输入设备。
6)。操作C:子进程把加工后的成品(输出数据)输出到输出管道。通常,程序的输出数据会输出到标准的输出设备,一般为屏幕,这里实现输出重定向,即把输出管道作为输出设备。
7)。操作D:把输出管道的数据写入输出文件
需要注意的是,管道的本质只是一个共享的内存区域。这个实验中,管道区域处于父进程的地址空间中,父进程的作用是提供环境和资源,并协调子进程进行加工。
程序源码:
代码:
[cpp] view plain copy
  1. #include <windows.h>   
  2. #include <iostream.h>  
  3.   
  4. const int BUFSIZE = 4096 ;   
  5. HANDLE  hChildStdinRd, hChildStdinWr, hChildStdinWrDup,   
  6.        hChildStdoutRd,hChildStdoutWr,hChildStdoutRdDup,   
  7.     hSaveStdin,    hSaveStdout;   
  8.   
  9. BOOL CreateChildProcess(LPTSTR);   
  10. VOID WriteToPipe(LPTSTR);   
  11. VOID ReadFromPipe(LPTSTR);   
  12. VOID ErrorExit(LPTSTR);   
  13. VOID ErrMsg(LPTSTR, BOOL);   
  14. void main( int argc, char *argv[] )   
  15. {    
  16.   // 处理输入参数  
  17.   if ( argc != 4 )  
  18.     return ;  
  19.   
  20.   // 分别用来保存命令行,输入文件名(CPP/C),输出文件名(保存编译信息)  
  21.   LPTSTR lpProgram = new char[ strlen(argv[1]) ] ;  
  22.   strcpy ( lpProgram, argv[1] ) ;  
  23.   LPTSTR lpInputFile = new char[ strlen(argv[2]) ];  
  24.   strcpy ( lpInputFile, argv[2] ) ;  
  25.   LPTSTR lpOutputFile = new char[ strlen(argv[3]) ] ;  
  26.   strcpy ( lpOutputFile, argv[3] ) ;      
  27.     
  28.   SECURITY_ATTRIBUTES saAttr;   
  29.   saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);   
  30.   saAttr.bInheritHandle = TRUE;   
  31.   saAttr.lpSecurityDescriptor = NULL;   
  32.      
  33.   /************************************************ 
  34.    *    redirecting child process's STDOUT  * 
  35.    ************************************************/  
  36.   hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);   
  37.     
  38.   if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))   
  39.     ErrorExit("Stdout pipe creation failed/n");   
  40.       
  41.   if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))   
  42.     ErrorExit("Redirecting STDOUT failed");   
  43.     
  44.   BOOL fSuccess = DuplicateHandle(  
  45.     GetCurrentProcess(),   
  46.     hChildStdoutRd,  
  47.         GetCurrentProcess(),   
  48.     &hChildStdoutRdDup ,  
  49.     0,  
  50.         FALSE,  
  51.         DUPLICATE_SAME_ACCESS);  
  52.     if( !fSuccess )  
  53.         ErrorExit("DuplicateHandle failed");  
  54.     CloseHandle(hChildStdoutRd);  
  55.     
  56.   /************************************************ 
  57.    *    redirecting child process's STDIN    * 
  58.    ************************************************/  
  59.   hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);   
  60.   
  61.   if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))   
  62.     ErrorExit("Stdin pipe creation failed/n");   
  63.     
  64.   if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd))   
  65.     ErrorExit("Redirecting Stdin failed");   
  66.     
  67.   fSuccess = DuplicateHandle(  
  68.     GetCurrentProcess(),   
  69.     hChildStdinWr,   
  70.     GetCurrentProcess(),  
  71.     &hChildStdinWrDup,   
  72.     0,   
  73.     FALSE,                   
  74.     DUPLICATE_SAME_ACCESS);   
  75.   if (! fSuccess)   
  76.     ErrorExit("DuplicateHandle failed");   
  77.   CloseHandle(hChildStdinWr);     
  78.   
  79.   /************************************************ 
  80.    *      创建子进程(即启动SAMPLE.EXE)    * 
  81.    ************************************************/  
  82.   fSuccess = CreateChildProcess( lpProgram );  
  83.   if ( !fSuccess )   
  84.     ErrorExit("Create process failed");   
  85.     
  86.   // 父进程输入输出流的还原设置  
  87.   if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin))   
  88.     ErrorExit("Re-redirecting Stdin failed/n");   
  89.   if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))   
  90.     ErrorExit("Re-redirecting Stdout failed/n");   
  91.   
  92.   WriteToPipe( lpInputFile ) ;  
  93.   ReadFromPipe( lpOutputFile );   
  94.           delete lpProgram ;  
  95.           delete lpInputFile ;  
  96.           delete lpOutputFile ;  
  97. }   
  98.   
  99. BOOL CreateChildProcess( LPTSTR lpProgram )   
  100. {   
  101.   PROCESS_INFORMATION piProcInfo;   
  102.   STARTUPINFO siStartInfo;  
  103.   BOOL bFuncRetn = FALSE;   
  104.     
  105.   ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );  
  106.   ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );  
  107.   siStartInfo.cb = sizeof(STARTUPINFO);   
  108.     
  109.   bFuncRetn = CreateProcess ( NULL, lpProgram, NULL, NULL, TRUE, /  
  110.                 0, NULL, NULL, &siStartInfo, &piProcInfo);  
  111.   if (bFuncRetn == 0)   
  112.   {  
  113.     ErrorExit("CreateProcess failed/n");  
  114.     return 0;  
  115.   }   
  116.   else   
  117.   {  
  118.     CloseHandle(piProcInfo.hProcess);  
  119.     CloseHandle(piProcInfo.hThread);  
  120.     return bFuncRetn;  
  121.   }  
  122. }  
  123.   
  124. VOID WriteToPipe( LPTSTR lpInputFile )   
  125. {   
  126.   HANDLE hInputFile = CreateFile(lpInputFile, GENERIC_READ, 0, NULL,   
  127.     OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);   
  128.   if (hInputFile == INVALID_HANDLE_VALUE)   
  129.     return ;  
  130.   
  131.   BOOL fSuccess ;  
  132.   DWORD dwRead, dwWritten;   
  133.   CHAR chBuf[BUFSIZE] = {0} ;   
  134.     
  135.   for (;;)   
  136.   {   
  137.     fSuccess = ReadFile( hInputFile, chBuf, BUFSIZE, &dwRead, NULL) ;  
  138.     if ( !fSuccess || dwRead == 0)  
  139.       break;   
  140.   
  141.     fSuccess = WriteFile( hChildStdinWrDup, chBuf, dwRead, &dwWritten, NULL) ;  
  142.     if ( !fSuccess )   
  143.       break;   
  144.   }   
  145.       
  146.   if (! CloseHandle(hChildStdinWrDup))   
  147.     ErrorExit("Close pipe failed/n");   
  148.   
  149.   CloseHandle ( hInputFile ) ;  
  150. }   
  151.   
  152. VOID ReadFromPipe( LPTSTR lpOutputFile )   
  153. {   
  154.   HANDLE hOutputFile = CreateFile( lpOutputFile, GENERIC_READ|GENERIC_WRITE,   
  155.     FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);   
  156.   if (hOutputFile == INVALID_HANDLE_VALUE)   
  157.     return ;  
  158.   
  159.   BOOL fSuccess ;  
  160.   DWORD dwRead, dwWritten;   
  161.   CHAR chBuf[BUFSIZE] = { 0 };   
  162.     
  163.   if (!CloseHandle(hChildStdoutWr))   
  164.     ErrorExit("Closing handle failed");   
  165.     
  166.   for (;;)   
  167.   {   
  168.     fSuccess = ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead, NULL) ;  
  169.     if( !fSuccess || dwRead == 0)   
  170.     {  
  171.       break;   
  172.     }  
  173.     fSuccess = WriteFile( hOutputFile, chBuf, dwRead, &dwWritten, NULL) ;  
  174.     if ( !fSuccess )   
  175.       break;   
  176.   }   
  177.   
  178.   CloseHandle ( hOutputFile ) ;  
  179. }   
  180. VOID ErrorExit (LPTSTR lpszMessage)   
  181. {   
  182.   MessageBox( 0, lpszMessage, 0, 0 );   
  183. }  
二、命名管道
命名管道具有以下几个特征:
(1)命名管道是双向的,所以两个进程可以通过同一管道进行交互。
(2)命名管道不但可以面向字节流,还可以面向消息,所以读取进程可以读取写进程发送的不同长度的消息。
(3)多个独立的管道实例可以用一个名称来命名。例如几个客户端可以使用名称相同的管道与同一个服务器进行并发通信。
(4)命名管道可以用于网络间两个进程的通信,而其实现的过程与本地进程通信完全一致。
实验目标:在客户端输入数据a和b,然后发送到服务器并计算a+b,然后把计算结果发送到客户端。可以多个客户端与同一个服务器并行通信。
界面设计:
难点所在:
实现的过程比较简单,但有一个难点。原本当服务端使用ConnectNamedPipe函数后,如果有客户端连接,就可以直接进行交互。原来我在实现过程中,当管道空闲时,管道的线程函数会无限(INFINITE)阻塞。若现在需要停止服务,就必须结束所有的线程,TernimateThread可以作为一个结束线程的方法,但我基本不用这个函数。一旦使用这个函数之后,目标线程就会立即结束,但如果此时的目标线程正在操作互斥资源、内核调用、或者是操作共享DLL的全局变量,可能会出现互斥资源无法释放、内核异常等现象。这里我用重叠I/0来解决这个问题,在创建PIPE时使用FILE_FLAG_OVERLAPPED标志,这样使用ConnectNamedPipe后会立即返回,但线程的阻塞由等待函数WaitForSingleObject来实现,等待OVERLAPPED结构的事件对象被设置。
客户端主要代码:
代码:
[cpp] view plain copy
  1. void CMyDlg::OnSubmit()   
  2. {  
  3.   // 打开管道  
  4.   HANDLE hPipe = CreateFile(".//Pipe//NamedPipe", GENERIC_READ | GENERIC_WRITE, /  
  5.     0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) ;  
  6.   if ( hPipe == INVALID_HANDLE_VALUE )  
  7.   {  
  8.     this->MessageBox ( "打开管道失败,服务器尚未启动,或者客户端数量过多" ) ;  
  9.     return ;  
  10.   }  
  11.   
  12.   DWORD nReadByte, nWriteByte ;  
  13.   char szBuf[1024] = {0} ;  
  14.   // 把两个整数(a,b)格式化为字符串  
  15.   sprintf ( szBuf, "%d %d", this->nFirst, this->nSecond ) ;  
  16.   // 把数据写入管道  
  17.   WriteFile ( hPipe, szBuf, strlen(szBuf), &nWriteByte, NULL ) ;  
  18.   
  19.   memset ( szBuf, 0, sizeof(szBuf) ) ;  
  20.   // 读取服务器的反馈信息  
  21.   ReadFile ( hPipe, szBuf, 1024, &nReadByte, NULL ) ;  
  22.   // 把返回信息格式化为整数  
  23.   sscanf ( szBuf, "%d", &(this->nResValue) ) ;  
  24.   this->UpdateData ( false ) ;  
  25.   CloseHandle ( hPipe ) ;  
  26. }  
服务端主要代码:
代码:
[cpp] view plain copy
  1. // 启动服务  
  2. void CMyDlg::OnStart()   
  3. {  
  4.   CString lpPipeName = ".//Pipe//NamedPipe" ;  
  5.   for ( UINT i = 0; i < nMaxConn; i++ )  
  6.   {  
  7.     // 创建管道实例  
  8.     PipeInst[i].hPipe =  CreateNamedPipe ( lpPipeName, PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, /  
  9.           PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT, nMaxConn, 0, 0, 1000, NULL ) ;  
  10.     if ( PipeInst[i].hPipe == INVALID_HANDLE_VALUE )  
  11.     {  
  12.       DWORD dwErrorCode = GetLastError () ;  
  13.       this->MessageBox ( "创建管道错误!" ) ;  
  14.       return ;  
  15.     }  
  16.     // 为每个管道实例创建一个事件对象,用于实现重叠IO  
  17.     PipeInst[i].hEvent  =  CreateEvent ( NULL, false, false, false ) ;  
  18.     // 为每个管道实例分配一个线程,用于响应客户端的请求  
  19.     PipeInst[i].hTread = AfxBeginThread ( ServerThread, &PipeInst[i], THREAD_PRIORITY_NORMAL ) ;  
  20.   }  
  21.     
  22.   this->SetWindowText ( "命名管道实例之服务器(运行)" ) ;  
  23.   this->MessageBox ( "服务启动成功" ) ;  
  24. }  
  25. // 停止服务  
  26. void CMyDlg::OnStop()   
  27. {  
  28.   DWORD dwNewMode = PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_NOWAIT ;  
  29.   for ( UINT i = 0; i < nMaxConn; i++ )  
  30.   {  
  31.     SetEvent ( PipeInst[i].hEvent ) ;  
  32.     CloseHandle ( PipeInst[i].hTread ) ;  
  33.     CloseHandle ( PipeInst[i].hPipe ) ;  
  34.   }  
  35.       
  36.   this->SetWindowText ( "命名管道实例之服务器" ) ;  
  37.   this->MessageBox ( "停止启动成功" ) ;  
  38. }  
  39.   
  40. // 线程服务函数  
  41. UINT ServerThread ( LPVOID lpParameter )  
  42. {  
  43.   DWORD  nReadByte = 0, nWriteByte = 0, dwByte = 0 ;    
  44.   char  szBuf[MAX_BUFFER_SIZE] = {0} ;  
  45.   PIPE_INSTRUCT  CurPipeInst = *(PIPE_INSTRUCT*)lpParameter ;  
  46.   OVERLAPPED OverLapStruct = { 0, 0, 0, 0, CurPipeInst.hEvent } ;  
  47.   while ( true )  
  48.   {  
  49.     memset ( szBuf, 0, sizeof(szBuf) ) ;    
  50.     // 命名管道的连接函数,等待客户端的连接(只针对NT)  
  51.     ConnectNamedPipe ( CurPipeInst.hPipe, &OverLapStruct ) ;  
  52.     // 实现重叠I/0,等待OVERLAPPED结构的事件对象  
  53.     WaitForSingleObject ( CurPipeInst.hEvent, INFINITE ) ;  
  54.     // 检测I/0是否已经完成,如果未完成,意味着该事件对象是人工设置,即服务需要停止  
  55.     if ( !GetOverlappedResult ( CurPipeInst.hPipe, &OverLapStruct, &dwByte, true ) )  
  56.       break ;  
  57.   
  58.     // 从管道中读取客户端的请求信息  
  59.     if ( !ReadFile ( CurPipeInst.hPipe, szBuf, MAX_BUFFER_SIZE, &nReadByte, NULL ) )  
  60.     {  
  61.       MessageBox ( 0, "读取管道错误!", 0, 0 ) ;  
  62.       break ;  
  63.     }  
  64.       
  65.     int a, b ;  
  66.     sscanf ( szBuf, "%d %d", &a, &b ) ;  
  67.     pMyDlg->nFirst    = a ;  
  68.     pMyDlg->nSecond    = b ;  
  69.     pMyDlg->nResValue  = a + b ;  
  70.     memset ( szBuf, 0, sizeof(szBuf) ) ;  
  71.     sprintf ( szBuf, "%d", pMyDlg->nResValue ) ;  
  72.     // 把反馈信息写入管道  
  73.     WriteFile ( CurPipeInst.hPipe, szBuf, strlen(szBuf), &nWriteByte, NULL ) ;  
  74.     pMyDlg->SetDlgItemInt ( IDC_FIRST, a, true ) ;  
  75.     pMyDlg->SetDlgItemInt ( IDC_SECOND, b, true ) ;  
  76.     pMyDlg->SetDlgItemInt ( IDC_RESULT, pMyDlg->nResValue, true ) ;  
  77.     // 断开客户端的连接,以便等待下一客户的到来  
  78.     DisconnectNamedPipe ( CurPipeInst.hPipe ) ;  
  79.   }  
  80.   
  81.   return 0 ;  
  82. }  
最后特别说明一下,此文章是看雪WIN32安全编程板块的斑竹北极星的,大家可以多多关注一下他的技术文章,看了几篇都认为很不错的。
链 接: http://bbs.pediy.com/showthread.php?t=26252
http://blog.csdn.net/yiruirui0507/article/details/6457806

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/458329.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

20分钟快速了解Redis

Redis可以说是目前最火爆的NoSQL数据库&#xff01; 过去几年&#xff0c;Memcached很盛行&#xff0c;现在有很多公司已将Memcached替换成了Redis。当然&#xff0c;很多人替换并不清楚为什么&#xff0c;只是感觉不想让主流抛弃&#xff0c;这也充分反映了目前Redis的强势。 …

进程通信例子

from&#xff1a;https://msdn.microsoft.com/zh-cn/library/system.diagnostics.process.beginoutputreadline(vvs.80).aspx?cs-save-lang1&cs-langcsharp#code-snippet-4备注可同步或异步读取 StandardOutput 流。Read、ReadLine 和 ReadToEnd 等方法对进程的输出流执行…

IDEA15 下运行Scala遇到问题以及解决办法

为了让Scala运行起来还是很麻烦&#xff0c;为了大家方便&#xff0c;还是记录下来&#xff1a; 1、首先我下载的是IDEA的社区版本&#xff0c;版本号为15. 2、下载安装scala插件&#xff1a; 2.1 进入设置菜单。 2.2 点击安装JetBrains plugin 2.3 输入scala查询插件&#xff…

使用try-with-resources替代try finally释放资源

2019独角兽企业重金招聘Python工程师标准>>> 1、旧社会 Java里&#xff0c;对于文件操作IO流、数据库连接等开销非常昂贵的资源&#xff0c;用完之后必须及时通过close方法将其关闭&#xff0c;否则资源会一直处于打开状态&#xff0c;直至程序停止&#xff0c;增加…

平板电脑离寿终正寝还有多远?

近期有评论称&#xff0c;因为大尺寸智能手机越来越普及&#xff0c;小尺寸平板正遭受着越来越严重的冲击&#xff0c;在这样的背景下&#xff0c;平板厂商也纷纷转攻超大尺寸平板市场&#xff0c;以此避开大尺寸智能手机的竞争&#xff0c;只是。这样的策略转变是否能扭转平板…

Swift 与 JSON 数据

转载自&#xff1a; http://www.cnblogs.com/theswiftworld/p/4660177.html 我们大家平时在开发 App 的时候&#xff0c;相信接触最多的就是 JSON 数据了。只要你的 App 有读取网络数据的功能&#xff0c;你就免不了要与 JSON 打交道。比如你做一个新闻 App&#xff0c;你要读取…

TeamViewer - 最好用强大的免费跨平台远程桌面控制软件 (支持电脑和手机)

from&#xff1a;很早以前 LYcHEE 就提到过&#xff0c;家中的潮人爷爷奶奶每天摆弄着电脑&#xff0c;看看新闻发发邮件&#xff0c;安享晚年生活。只是意料之中的&#xff0c;电脑上莫名出现各种问题&#xff1f;不翼而飞的图标&#xff1f;照片又忘记怎么导出了&#xff1f;…

【设计模式】7、桥接模式

桥接模式就是对一个类的方法进行抽象化&#xff0c;吧不相关的因素提取出来&#xff0c;发展出第二个类 1 package com.shejimoshi.structural.Bridge;2 3 4 /**5 * 功能&#xff1a;桥接模式使用6 * 意图&#xff1a;将抽象部分与它的实现部分分离&#xff0c;使他们都…

TeamViewer免费版和付费版有什么不同

提到远程控制软件 TeamViewer无疑是目前业内知名度比较高的一款&#xff0c;所以说到远程控制软件可能大部分人首先想到的就是TeamViewer。在使用功能上&#xff0c;它支持远程桌面控制、文件传输、远程计算机锁定、视频会话、主控方和被控方身份互换&#xff0c;远程管理无人执…

【代码笔记】iOS-翻书效果的实现

代码&#xff1a; RootViewController.m #import "RootViewController.h"interface RootViewController ()endimplementation RootViewController- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {self [super initWithNibName:…

Halcon—Tuple中符号的含义

2014年08月08日 21:20:30阅读数&#xff1a;5429实例一&#xff08;3d_coordinates.hdev&#xff09;&#xff1a;for I : 1 to NumImages by 1read_image (Image, calib/calib-3d-coord-I$02d)——C:\Program Files\MVTec\HALCON-10.0\images\的calib文件夹中开头是calib-3d-c…

Halcon学习笔记(三)---数据类型

Halcon学习笔记&#xff08;三&#xff09;---数据类型halcon只能在单独行进行注释&#xff0c;不能在语句后面进行注释。1、tuple(元组&#xff0c;重数)赋值符号“&#xff1a;”tuple算子&#xff1a;&#xff08;1&#xff09;变量定义与加减乘除运算代码如下&#xff1a;*…

论文笔记之:RATM: RECURRENT ATTENTIVE TRACKING MODEL

RATM: RECURRENT ATTENTIVE TRACKING MODEL ICLR 2016 本文主要内容是 结合 RNN 和 attention model 用来做目标跟踪。 其中模型的组成主要是&#xff1a; 1. an attention model 主要用来从输入图像中提取 patch&#xff1b; 2. RNN 用来预测 attention 参数&#xff0c;即&am…

【分享】WeX5的正确打开方式(5)——绑定机制

今天继续WeX5的绑定机制。 需求分析 记账本要实现的效果就是可以展示所有账单&#xff0c;还能实时动态编辑每一笔账单&#xff0c;官方案例的效果图如下&#xff1a; 展示页&#xff1a; 编辑页 个人觉得官方案例加入了许多元素&#xff0c;不熟悉的同学每一个点都很难理解&am…

关于未捕获异常的处理(WPF)

转载自&#xff1a;http://www.cnblogs.com/chenxizhang/p/3280947.html 这一篇文章来谈谈对于WPF应用程序开发中的未捕获异常的处理。 首先&#xff0c;我们当然是要求应用程序开发人员&#xff0c;尽可能地在程序可能出现异常的地方都去捕捉异常&#xff0c;使用try…catch的…

设计模式--23、访问者模式

访问者模式是一种较为复杂的行为型设计模式&#xff0c;它包含访问者和被访问元素两个主要组成部分&#xff0c;这些被访问的元素通常具有不同的类型&#xff0c;且不同的访问者可以对它们进行不同的访问操作。例如处方单中的各种药品信息就是被访问的元素&#xff0c;而划价人…

『协议』XML-RPC 协议规格说明

为什么80%的码农都做不了架构师&#xff1f;>>> 这篇文章提供所有实现XML-RPC协议所需要的内容。 一览 XML-RPC是一个工作在因特网上的远端程序调用&#xff08;Remote Procedure Calling&#xff09;协议。 XML-RPC消息是一个HTTP-POST请求&#xff08;Request&…

Qt之QLineEdit详解(附源码)

原博客地址&#xff1a;http://blog.csdn.net/liang19890820/article/details/52044639&#xff0c;感谢原作者总结和分享。 简述 QLineEdit是一个单行文本输入框。 QLineEdit允许用户输入和编辑单行纯文本&#xff0c;提供了很多有用的编辑功能&#xff0c;包括&#xff1a;撤…

C#json数据的序列化和反序列化(将数据转换为对象或对象集合)

引用 System.Runtime.Serialization.Json 转载于:https://www.cnblogs.com/a849788087/p/5645828.html

位图(bmp)文件格式分析

from&#xff1a;https://blog.csdn.net/qingchuwudi/article/details/25785307 位图(bmp)文件格式分析 作者&#xff1a;深蓝&#xff08;由博主分享&#xff09; 一、什么是位图 计算机能以位图和矢量图格式显示图像。 1、位图(Bitmap)&#xff1a; 图像又称点阵图或光…