posts - 131, comments - 12, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

开源中国社区
http://www.oschina.net/

美国
http://sourceforge.net/



 Ptypes一个开源轻量级的c++库,包括对一些I/O操作、网络通信、多线程和异常处理的封装。虽然代码有限,包括的内容不少,麻雀虽小,五脏俱全。
    提高:STL Boost和STL ACE
    Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的发动机之一。 Boost库由C++标准委员会库工作组成员发起,其中有些内容有望成为下一代C++标准库内容。在C++社区中影响甚大,是不折不扣的“准”标准库。 Boost由于其对跨平台的强调,对标准C++的强调,与编写平台无关。大部分boost库功能的使用只需包括相应头文件即可,少数(如正则表达式库,文 件系统库等)需要链接库。但Boost中也有很多是实验性质的东西,在实际的开发中实用需要谨慎。boost 在一些播放软件和音效中指增强,比如Bass Boost,低音增强。
    Adaptive Communication Environment(自适配通信环境),简称ACE。为一个以C++的Template技术所做成的开放源代码的可跨平台的网络应用程序的程序库套件。它提供了socket/threading/memory management等多种系统调用的面对对象的wrapper,使C++通信软件开发更加简单。

http://www.cppblog.com/


个人觉得比较经典的C++ 开源项目,整理如下:

 

1 、log4cplus

log4cplus 是C++ 编写的开源的日志系统, 功能非常全面。C++ 版的log4j

网址:http://log4cplus.sourceforge.net/

 

2 、Glog

Google Glog 是一个C++ 语言的应用级日志记录框架,提供了 C++ 风格的流操作和各种助手宏。

SVN :http://google-glog.googlecode.com/svn/trunk

 

3 、memcached

memcached 是一套分布式的快取系统,当初是Danga Interactive 为了LiveJournal 所发展的,但目前被许多软件(如MediaWiki )所使用。这是一套开放源代码软件,以BSD license 授权释出。

memcached 缺乏认证以及安全管制,这代表应该将memcached 服务器放置在防火墙后。

SVN :http://code.sixapart.com/svn/memcached

 


4 、 TinyXML

TinyXML 是目前非常流行的一款基于DOM 模型的XML 解析器,简单易用且小巧 玲珑,非常适合存储简单数据,配置文件,对象序列化等数据量不是很大的操作

网址:http://www.grinninglizard.com/tinyxml/

 

5 、OpenSSL

OpenSSL 包含一个命令行工具用来完成OpenSSL 库中的所有功能,更好的是,它可能已经安装到你的系统中了。

OpenSSL 是一个强大的安全套接字层密码库,Apache 使用它加密HTTPS ,OpenSSH 使用它加密SSH ,但是,你不应该只将其作为一个库来使用,它还是一个多用途的、跨平台的密码工具。

网址:http://www.openssl.org/source/

 

6 、xerces

Xerces是由Apache组织所推动的一项XML文档解析开源项目,它目前有多种语言版本包括JAVA、C++、PERL、COM等。

  网址:http://xerces.apache.org/xerces-c/download.cgi

 

7 、Boost

Boost 库是一个经过千锤百炼、可移植、提供源代码的C++ 库,作为标准库的后备,是C++ 标准化进程的发动机之一。 Boost 库由C++标准委员会库工作组成员发起,在C++ 社区中影响甚大,其成员已近2000 人。 Boost 库为我们带来了最新、最酷、最实用的技术,是不折不扣的“ 准” 标准库。

网址:http://www.boost.org/

 


8、Zlib

Zlib 软件包包含 zlib 库,很多程序中的压缩或者解压缩函数都会用到这个库

网址:http://www.zlib.net/

 

里面有几个好的开源项目比如日志系统,还有XML解析的程序,应该都是不错的程序,我们应该能从中学习到些什么,然后用到项目中去,或者添加功能到里面去。如果有时间的话,真想静下心来看一看。

posted @ 2013-02-16 15:41 盛胜 阅读(283) | 评论 (0)编辑 收藏

     摘要: 12345678910111213141516171819202122#include <stdio.h>#include <io.h>  int main (void){    _finddata_t fileDir;    ...  阅读全文

posted @ 2013-02-16 15:26 盛胜 阅读(434) | 评论 (0)编辑 收藏

IGraphBuilder *m_pGraph ;
IMediaControl *m_pControl ;
IMediaEvent   *m_pEvent ;
CString strfilepath;
CFileDialog FileDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,"Video Files(*.avi;*.avi)|*.avi;*.avi||");
if(FileDlg.DoModal()==IDOK)
{
strfilepath = FileDlg.GetPathName();
}
else
{
return ;
}
m_bstr = strfilepath;
m_pGraph = NULL;
m_pControl = NULL;
m_pEvent = NULL;
// Initialize the COM library.
m_hr = CoInitialize(NULL);
if (FAILED(m_hr))
{
printf("ERROR - Could not initialize COM library");
return;
}
 
// Create the filter graph manager and query for interfaces.
m_hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
IID_IGraphBuilder, (void **)&m_pGraph);
if (FAILED(m_hr))
{
printf("ERROR - Could not create the Filter Graph Manager.");
return;
}
 
m_hr = m_pGraph->QueryInterface(IID_IMediaControl, (void **)&m_pControl);
m_hr = m_pGraph->QueryInterface(IID_IMediaEvent, (void **)&m_pEvent);
// Build the graph. IMPORTANT: Change this string to a file on your system.
m_hr = m_pGraph->RenderFile(m_bstr, NULL);
if (SUCCEEDED(m_hr))
{
// Run the graph.
m_hr = m_pControl->Run();
if (SUCCEEDED(m_hr))
{
// Wait for completion.
long evCode;
m_pEvent->WaitForCompletion(INFINITE, &evCode);
 
// Note: Do not use INFINITE in a real application, because it
// can block indefinitely.
}
}
m_pControl->Release();
m_pEvent->Release();
m_pGraph->Release();
CoUninitialize();

posted @ 2013-01-22 09:33 盛胜 阅读(338) | 评论 (0)编辑 收藏

#include "comutil.h"
#pragma comment(lib, "comsupp.lib")
#pragma comment(lib, "comsuppw.lib")

_bstr_t bstr;
bstr = strPath;
ShellExecute(m_hWnd, "open", bstr, NULL, NULL, SW_SHOWNORMAL);

posted @ 2013-01-18 17:18 盛胜 阅读(292) | 评论 (0)编辑 收藏

CWnd *pWnd = CWnd::FromHandle(GetDlgItem(hWnd,ID));
m_Camerapwnd = pWnd;

posted @ 2013-01-16 14:01 盛胜 阅读(236) | 评论 (0)编辑 收藏

网上很多都说录制了之后视频文件为0k,或者是打不开。

其实,这个原因主要与2方面有关:

  1. OpenCV生成的视频的编码格式有关。

  2. 非法退出录取有关(我用200次循环解决。或者可以用Timer。或者用其他键处理)

 

vs2008 win32控制台程序

复制代码
 1 #include "cv.h"
2 #include "cxcore.h"
3 #include "highgui.h"
4 #include <iostream>
5
6 using namespace std;
7 int main()
8 {
9 CvCapture* capture=cvCaptureFromCAM(-1);
10 CvVideoWriter* video=NULL;
11 IplImage* frame=NULL;
12 int n;
13 if(!capture) //如果不能打开摄像头给出警告
14 {
15 cout<<"Can not open the camera."<<endl;
16 return -1;
17 }
18 else
19 {
20 frame=cvQueryFrame(capture); //首先取得摄像头中的一帧
21 video=cvCreateVideoWriter("camera.avi", CV_FOURCC('X', 'V', 'I', 'D'), 25,
22 cvSize(frame->width,frame->height)); //创建CvVideoWriter对象并分配空间
23 //保存的文件名为camera.avi,编码要在运行程序时选择,大小就是摄像头视频的大小,帧频率是32
24 if(video) //如果能创建CvVideoWriter对象则表明成功
25 {
26 cout<<"VideoWriter has created."<<endl;
27 }
28
29 cvNamedWindow("Camera Video",1); //新建一个窗口
30 int i = 0;
31 while(i <= 200) // 让它循环200次自动停止录取
32 {
33 frame=cvQueryFrame(capture); //从CvCapture中获得一帧
34 if(!frame)
35 {
36 cout<<"Can not get frame from the capture."<<endl;
37 break;
38 }
39 n=cvWriteFrame(video,frame); //判断是否写入成功,如果返回的是1,表示写入成功
40 cout<<n<<endl;
41 cvShowImage("Camera Video",frame); //显示视频内容的图片
42 i++;
43 if(cvWaitKey(2)>0)
44 break; //有其他键盘响应,则退出
45 }
46
47 cvReleaseVideoWriter(&video);
48 cvReleaseCapture(&capture);
49 cvDestroyWindow("Camera Video");
50 }
51 return 0;
52 }

posted @ 2013-01-16 11:18 盛胜 阅读(9891) | 评论 (4)编辑 收藏

http://blog.csdn.net/weixingstudio/article/details/7360941

posted @ 2013-01-15 16:30 盛胜 阅读(283) | 评论 (0)编辑 收藏

http://hi.baidu.com/andywangcn/item/50d640c325290a2aef4665c4
1、 启动线程:

CWinThread* AfxBeginThread( 线程函数,this );

2、通常导致线程终止的两种情况是:控制函数退出或不允许线程完成运行。如果字处理器使用后台打印线程,若成功完成打印,则控制函数将正常终止。但是,如果用户要取消打印,后台打印线程则不得不提前终止。本主题介绍如何实现每一种情况,以及在终止后如何获取线程的退出代码。

(1)正常线程终止

对于辅助线程,正常线程终止很简单:退出控制函数并返回表示终止原因的值。可以使用 函数或 return 语句。一般情况下,0 表示成功完成,但这取决于您自己。

对于用户界面线程,该过程也很简单:从用户界面线程内调用 Platform SDK 中的 。PostQuitMessage 采用的唯一参数是线程的退出代码。对于辅助线程,0 通常表示成功完成。

(2)过早的线程终止

过早终止线程几乎一样简单:从线程内调用 。将所需的退出代码作为唯一参数传递。这将停止执行线程、解除对线程堆栈的分配、分离附加到线程的所有 DLL 并从内存中删除线程对象。

必须从要终止的线程内调用 AfxEndThread。如果要从其他线程终止线程,必须设置两个线程间的通信方法。

举一个例子:

可以创建一个信号量,用WaitForSingleObject函数来检测该信号量的状态。

成员变量 m_hThreadEvent;

m_hThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );

线程的执行函数:

         for ( ; ; )

         {         DWORD dwRetVal;

                   dwRetVal = WaitForSingleObject( m_hThreadEvent, 100 );

                   if ( dwRetVal == WAIT_TIMEOUT )

                        {                    // TODO:

                   }

                   else

                   {

                            // stop receive text thread.

                            DWORD dwExitCode;

                            GetExitCodeThread( m_pThreadRecv->m_hThread, &dwExitCode );

                            AfxEndThread( dwExitCode, TRUE );

                   }

         }

    要结束线程时,使用SetEvent,将信号量置为有信号。

    该线程是在信号量有信号时,退出。

(3)TerminateThread

在CWinThread对象中有线程的句柄,可以使用该句柄强行杀死线程。但是不推荐使用这种方式,当可以正常结束的时候,选择前两种方法较好。

检索线程的退出代码

若要获取辅助线程或用户界面线程的退出代码,请调用 函数。有关此函数的信息,请参见 Platform SDK。此函数获取线程(存储在 CWinThread 对象的 m_hThread 数据成员中)的句柄和 DWORD 的地址。

如果线程仍然是活动的,GetExitCodeThread 将 STILL_ACTIVE 放置在提供的 DWORD 地址中;否则将退出代码放置在该地址中。

检索 对象的退出代码还需要一步。默认情况下,当 CWinThread 线程终止时,删除该线程对象。这意味着不能访问 m_hThread 数据成员,因为 CWinThread 对象不再存在。若要避免出现这种情况,请执行以下操作之一:

  • 将 m_bAutoDelete 数据成员设置为 FALSE。这使 CWinThread 对象在线程终止后仍可以继续存在。然后可以在线程终止后,访问 m_hThread 数据成员。但是,如果使用此方法,就得销毁 CWinThread 对象,因为框架不会自动删除该对象。这是首选方法。

  • 单独存储线程的句柄。创建线程后,(使用 ::DuplicateHandle)将其 m_hThread 数据成员复制到其他变量,并通过该变量访问该成员。这样,终止后即会自动删除对象,并且仍然可以找到线程终止的原因。请注意:在可以复制句柄之前,线程不终止。执行此操作的最安全的方式是将 CREATE_SUSPENDED 传递到 ,存储句柄,然后通过调用 继续执行线程。

任一方法都可以使您确定 CWinThread 对象终止的原因。

posted @ 2013-01-15 11:00 盛胜 阅读(9729) | 评论 (0)编辑 收藏

http://www.cnblogs.com/zqrferrari/archive/2010/07/07/1773113.html
MFC 多线程及线程同步

一、MFC对多线程编程的支持

  MFC中有两类线程,分别称之为工作者线程和用户界面线程。二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环。
  工作者线程没有消息机制,通常用来执行后台计算和维护任务,如冗长的计算过程,打印机的后台打印等。用户界面线程一般用于处理独立于其他线程执行之外的用户输入,响应用户及系统所产生的事件和消息等。但对于Win32的API编程而言,这两种线程是没有区别的,它们都只需线程的启动地址即可启动线程来执行任务。
  在MFC中,一般用全局函数AfxBeginThread()来创建并初始化一个线程的运行,该函数有两种重载形式,分别用于创建工作者线程和用户界面线程。两种重载函数原型和参数分别说明如下:

  (1) CWinThread* AfxBeginThread(

        AFX_THREADPROC pfnThreadProc,
            LPVOID pParam,
            int nPriority = THREAD_PRIORITY_NORMAL,
            UNT nStackSize = 0,
            DWORD dwCreateFlags = 0,
            LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
           );//用于创建工作者线程

  PfnThreadProc:指向工作者线程的执行函数的指针,线程函数原型必须声明如下:

  UINT ExecutingFunction(LPVOID pParam);

  请注意,ExecutingFunction()应返回一个UINT类型的值,用以指明该函数结束的原因。一般情况下,返回0表明执行成功。

  • pParam:      一个32位参数,执行函数将用某种方式解释该值。它可以是数值,或是指向一个结构的指针,甚至可以被忽略;
  • nPriority:     线程的优先级。如果为0,则线程与其父线程具有相同的优先级;
  • nStackSize:   线程为自己分配堆栈的大小,其单位为字节。如果nStackSize被设为0,则线程的堆栈被设置成与父线程堆栈相同大小;
  • dwCreateFlags:如果为0,则线程在创建后立刻开始执行。如果为CREATE_SUSPEND,则线程在创建后立刻被挂起;
  • lpSecurityAttrs:线程的安全属性指针,一般为NULL;

  (2) CWinThread* AfxBeginThread(

       CRuntimeClass* pThreadClass,
            int nPriority = THREAD_PRIORITY_NORMAL,
            UNT nStackSize = 0,
            DWORD dwCreateFlags = 0,
            LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
           ); 

  pThreadClass 是指向 CWinThread 的一个导出类的运行时类对象的指针,该导出类定义了被创建的用户界面线程的启动、退出等;其它参数的意义同形式1。使用函数的这个原型生成的线程也有消息机制,在以后的例子中我们将发现同主线程的机制几乎一样。

  下面我们对CWinThread类的数据成员及常用函数进行简要说明。

  • m_hThread:     当前线程的句柄;
  • m_nThreadID:   当前线程的ID;
  • m_pMainWnd: 指向应用程序主窗口的指针
  BOOL CWinThread::CreateThread(DWORD dwCreateFlags=0,UINT nStackSize=0,LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);

  该函数中的dwCreateFlags、nStackSize、lpSecurityAttrs参数和API函数CreateThread中的对应参数有相同含义,该函数执行成功,返回非0值,否则返回0。
  一般情况下,调用AfxBeginThread()来一次性地创建并启动一个线程,但是也可以通过两步法来创建线程:首先创建CWinThread类的一个对象,然后调用该对象的成员函数CreateThread()来启动该线程。

  virtual BOOL CWinThread::InitInstance();

  重载该函数以控制用户界面线程实例的初始化。初始化成功则返回非0值,否则返回0。用户界面线程经常重载该函数,工作者线程一般不使用InitInstance()。

  virtual int CWinThread::ExitInstance();

  在线程终结前重载该函数进行一些必要的清理工作。该函数返回线程的退出码,0表示执行成功,非0值用来标识各种错误。同InitInstance()成员函数一样,该函数也只适用于用户界面线程。

 

二、MFC中线程同步

 在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作。更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解。正常情况下对这种处理结果的了解应当在其处理任务完成后进行。
  如果不采取适当的措施,其他线程往往会在线程处理任务结束前就去访问处理结果,这就很有可能得到有关处理结果的错误了解。例如,多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题。如果一个线程负责改变此变量的值,而其他线程负责同时读取变量内容,则不能保证读取到的数据是经过写线程修改后的。
  为了确保读线程读取到的是经过修改的变量,就必须在向变量写入数据时禁止其他线程对其的任何访问,直至赋值过程结束后再解除对其他线程的访问限制。象这种保证线程能了解其他线程任务处理结束后的处理结果而采取的保护措施即为线程同步。
  线程的同步可分用户模式的线程同步和内核对象的线程同步两大类。用户模式中线程的同步方法主要有原子访问和临界区等方法。其特点是同步速度特别快,适合于对线程运行速度有严格要求的场合。
  内核对象的线程同步则主要由事件、等待定时器、信号量以及信号灯等内核对象构成。由于这种同步机制使用了内核对象,使用时必须将线程从用户模式切换到内核模式,而这种转换一般要耗费近千个CPU周期,因此同步速度较慢,但在适用性上却要远优于用户模式的线程同步方式。

  

  1.临界区
 
 临界区(Critical Section)是一段独占对某些共享资源访问的代码,在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。
  临界区在使用时以CRITICAL_SECTION结构对象保护共享资源,并分别用EnterCriticalSection()和LeaveCriticalSection()函数去标识和释放一个临界区。所用到的CRITICAL_SECTION结构对象必须经过InitializeCriticalSection()的初始化后才能使用,而且必须确保所有线程中的任何试图访问此共享资源的代码都处在此临界区的保护之下。否则临界区将不会起到应有的作用,共享资源依然有被破坏的可能。

代码
  在使用临界区时,一般不允许其运行时间过长,只要进入临界区的线程还没有离开,其他所有试图进入此临界区的线程都会被挂起而进入到等待状态,并会在一定程度上影响。程序的运行性能。尤其需要注意的是不要将等待用户输入或是其他一些外界干预的操作包含到临界区。如果进入了临界区却一直没有释放,同样也会引起其他线程的长时间等待。换句话说,在执行了EnterCriticalSection()语句进入临界区后无论发生什么,必须确保与之匹配的LeaveCriticalSection()都能够被执行到。可以通过添加结构化异常处理代码来确保LeaveCriticalSection()语句的执行。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。
  MFC为临界区提供有一个CCriticalSection类,使用该类进行线程同步处理是非常简单的,只需在线程函数中用CCriticalSection类成员函数Lock()和UnLock()标定出被保护代码片段即可。对于上述代码,可通过CCriticalSection类将其改写如下:

代码

 

  2.事件内核对象

  在前面讲述线程通信时曾使用过事件内核对象来进行线程间的通信,除此之外,事件内核对象也可以通过通知操作的方式来保持线程的同步。对于前面那段使用临界区保持线程同步的代码可用事件对象的线程同步方法改写如下:

代码

  在创建线程前,首先创建一个可以自动复位的事件内核对象hEvent,而线程函数则通过WaitForSingleObject()等待函数无限等待hEvent的置位,只有在事件置位时WaitForSingleObject()才会返回,被保护的代码将得以执行。对于以自动复位方式创建的事件对象,在其置位后一被WaitForSingleObject()等待到就会立即复位,也就是说在执行ThreadProc12()中的受保护代码时,事件对象已经是复位状态的,这时即使有ThreadProc13()对CPU的抢占,也会由于WaitForSingleObject()没有hEvent的置位而不能继续执行,也就没有可能破坏受保护的共享资源。在ThreadProc12()中的处理完成后可以通过SetEvent()对hEvent的置位而允许ThreadProc13()对共享资源g_cArray的处理。这里SetEvent()所起的作用可以看作是对某项特定任务完成的通知。
  使用临界区只能同步同一进程中的线程,而使用事件内核对象则可以对进程外的线程进行同步,其前提是得到对此事件对象的访问权。可以通过OpenEvent()函数获取得到,其函数原型为:

HANDLE OpenEvent(
 DWORD dwDesiredAccess,  
// 访问标志
 BOOL bInheritHandle,    // 继承标志
 LPCTSTR lpName          // 指向事件对象名的指针
); 
  如果事件对象已创建(在创建事件时需要指定事件名),函数将返回指定事件的句柄。对于那些在创建事件时没有指定事件名的事件内核对象,可以通过使用内核对象的继承性或是调用DuplicateHandle()函数来调用CreateEvent()以获得对指定事件对象的访问权。在获取到访问权后所进行的同步操作与在同一个进程中所进行的线程同步操作是一样的。
  如果需要在一个线程中等待多个事件,则用WaitForMultipleObjects()来等待。WaitForMultipleObjects()与WaitForSingleObject()类似,同时监视位于句柄数组中的所有句柄。这些被监视对象的句柄享有平等的优先权,任何一个句柄都不可能比其他句柄具有更高的优先权。WaitForMultipleObjects()的函数原型为:
DWORD WaitForMultipleObjects(
 DWORD nCount,              
// 等待句柄数
 CONST HANDLE *lpHandles,   // 句柄数组首地址
 BOOL fWaitAll,             // 等待标志
 DWORD dwMilliseconds       // 等待时间间隔
);

  参数nCount指定了要等待的内核对象的数目,存放这些内核对象的数组由lpHandles来指向。fWaitAll对指定的这nCount个内核对象的两种等待方式进行了指定,为TRUE时当所有对象都被通知时函数才会返回,为FALSE则只要其中任何一个得到通知就可以返回。dwMilliseconds在这里的作用与在WaitForSingleObject()中的作用是完全一致的。如果等待超时,函数将返回WAIT_TIMEOUT。如果返回WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1中的某个值,则说明所有指定对象的状态均为已通知状态(当fWaitAll为TRUE时)或是用以减去WAIT_OBJECT_0而得到发生通知的对象的索引(当fWaitAll为FALSE时)。如果返回值在WAIT_ABANDONED_0与WAIT_ABANDONED_0+nCount-1之间,则表示所有指定对象的状态均为已通知,且其中至少有一个对象是被丢弃的互斥对象(当fWaitAll为TRUE时),或是用以减去WAIT_OBJECT_0表示一个等待正常结束的互斥对象的索引(当fWaitAll为FALSE时)。 下面给出的代码主要展示了对WaitForMultipleObjects()函数的使用。通过对两个事件内核对象的等待来控制线程任务的执行与中途退出:

代码

  MFC为事件相关处理也提供了一个CEvent类,共包含有除构造函数外的4个成员函数PulseEvent()、ResetEvent()、SetEvent()和UnLock()。在功能上分别相当与Win32 API的PulseEvent()、ResetEvent()、SetEvent()和CloseHandle()等函数。而构造函数则履行了原CreateEvent()函数创建事件对象的职责,其函数原型为:
  CEvent(BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );

 

  3.信号量内核对象

  信号量(Semaphore)内核对象对线程的同步方式与前面几种方法不同,它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。在用CreateSemaphore()创建信号量时即要同时指出允许的最大资源计数和当前可用资源计数。一般是将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的访问,当前可用资源计数就会减1,只要当前可用资源计数是大于0的,就可以发出信号量信号。但是当前可用计数减小到0时则说明当前占用资源的线程数已经达到了所允许的最大数目,不能在允许其他线程的进入,此时的信号量信号将无法发出。线程在处理完共享资源后,应在离开的同时通过ReleaseSemaphore()函数将当前可用资源计数加1。在任何时候当前可用资源计数决不可能大于最大资源计数。
  使用信号量内核对象进行线程同步主要会用到CreateSemaphore()、OpenSemaphore()、ReleaseSemaphore()、WaitForSingleObject()和WaitForMultipleObjects()等函数。其中,CreateSemaphore()用来创建一个信号量内核对象,其函数原型为:

HANDLE CreateSemaphore(
 LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, 
// 安全属性指针
 LONG lInitialCount,               // 初始计数
 LONG lMaximumCount,               // 最大计数
 LPCTSTR lpName                  // 对象名指针
);  

  参数lMaximumCount是一个有符号32位值,定义了允许的最大资源计数,最大取值不能超过4294967295。lpName参数可以为创建的信号量定义一个名字,由于其创建的是一个内核对象,因此在其他进程中可以通过该名字而得到此信号量。OpenSemaphore()函数即可用来根据信号量名打开在其他进程中创建的信号量,函数原型如下:

HANDLE OpenSemaphore(
 DWORD dwDesiredAccess,   
// 访问标志
 BOOL bInheritHandle,    // 继承标志
 LPCTSTR lpName        // 信号量名
); 

  在线程离开对共享资源的处理时,必须通过ReleaseSemaphore()来增加当前可用资源计数。否则将会出现当前正在处理共享资源的实际线程数并没有达到要限制的数值,而其他线程却因为当前可用资源计数为0而仍无法进入的情况。ReleaseSemaphore()的函数原型为:

BOOL ReleaseSemaphore(
 HANDLE hSemaphore, 
   // 信号量句柄
 LONG lReleaseCount,   // 计数递增数量
 LPLONG lpPreviousCount  // 先前计数
);

  该函数将lReleaseCount中的值添加给信号量的当前资源计数,一般将lReleaseCount设置为1,如果需要也可以设置其他的值。WaitForSingleObject()和WaitForMultipleObjects()主要用在试图进入共享资源的线程函数入口处,主要用来判断信号量的当前可用资源计数是否允许本线程的进入。只有在当前可用资源计数值大于0时,被监视的信号量内核对象才会得到通知。
  信号量的使用特点使其更适用于对Socket(套接字)程序中线程的同步。例如,网络上的HTTP服务器要对同一时间内访问同一页面的用户数加以限制,这时可以为没一个用户对服务器的页面请求设置一个线程,而页面则是待保护的共享资源,通过使用信号量对线程的同步作用可以确保在任一时刻无论有多少用户对某一页面进行访问,只有不大于设定的最大用户数目的线程能够进行访问,而其他的访问企图则被挂起,只有在有用户退出对此页面的访问后才有可能进入。下面给出的示例代码即展示了类似的处理过程:

代码

  在MFC中,通过CSemaphore类对信号量作了表述。该类只具有一个构造函数,可以构造一个信号量对象,并对初始资源计数、最大资源计数、对象名和安全属性等进行初始化,其原型如下:

   CSemaphore( LONG lInitialCount = 1, LONG lMaxCount = 1, LPCTSTR pstrName = NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL );

  在构造了CSemaphore类对象后,任何一个访问受保护共享资源的线程都必须通过CSemaphore从父类CSyncObject类继承得到的Lock()和UnLock()成员函数来访问或释放CSemaphore对象。与前面介绍的几种通过MFC类保持线程同步的方法类似,通过CSemaphore类也可以将前面的线程同步代码进行改写,这两种使用信号量的线程同步方法无论是在实现原理上还是从实现结果上都是完全一致的。下面给出经MFC改写后的信号量线程同步代码:

代码

 

     4.互斥内核对象

     互斥(Mutex)是一种用途非常广泛的内核对象。能够保证多个线程对同一共享资源的互斥访问。同临界区有些类似,只有拥有互斥对象的线程才具有访问资源的权限,由于互斥对象只有一个,因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出,以便其他线程在获得后得以访问资源。与其他几种内核对象不同,互斥对象在操作系统中拥有特殊代码,并由操作系统来管理,操作系统甚至还允许其进行一些其他内核对象所不能进行的非常规操作。

     以互斥内核对象来保持线程同步可能用到的函数主要有CreateMutex()、OpenMutex()、ReleaseMutex()、WaitForSingleObject()和WaitForMultipleObjects()等。在使用互斥对象前,首先要通过CreateMutex()或OpenMutex()创建或打开一个互斥对象。CreateMutex()函数原型为:

     HANDLE CreateMutex(
       LPSECURITY_ATTRIBUTES lpMutexAttributes, // 安全属性指针
       BOOL bInitialOwner, // 初始拥有者
       LPCTSTR lpName // 互斥对象名
     );

     参数bInitialOwner主要用来控制互斥对象的初始状态。一般多将其设置为FALSE,以表明互斥对象在创建时并没有为任何线程所占有。如果在创建互斥对象时指定了对象名,那么可以在本进程其他地方或是在其他进程通过OpenMutex()函数得到此互斥对象的句柄。OpenMutex()函数原型为:

    HANDLE OpenMutex(
      DWORD dwDesiredAccess, // 访问标志
      BOOL bInheritHandle, // 继承标志
      LPCTSTR lpName // 互斥对象名
    );

     当目前对资源具有访问权的线程不再需要访问此资源而要离开时,必须通过ReleaseMutex()函数来释放其拥有的互斥对象,其函数原型为:

    BOOL ReleaseMutex(HANDLE hMutex);

    其唯一的参数hMutex为待释放的互斥对象句柄。至于WaitForSingleObject()和WaitForMultipleObjects()等待函数在互斥对象保持线程同步中所起的作用与在其他内核对象中的作用是基本一致的,也是等待互斥内核对象的通知。但是这里需要特别指出的是:在互斥对象通知引起调用等待函数返回时,等待函数的返回值不再是通常的WAIT_OBJECT_0(对于WaitForSingleObject()函数)或是在WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1之间的一个值(对于WaitForMultipleObjects()函数),而是将返回一个WAIT_ABANDONED_0(对于WaitForSingleObject()函数)或是在WAIT_ABANDONED_0到WAIT_ABANDONED_0+nCount-1之间的一个值(对于WaitForMultipleObjects()函数)。以此来表明线程正在等待的互斥对象由另外一个线程所拥有,而此线程却在使用完共享资源前就已经终止。除此之外,使用互斥对象的方法在等待线程的可调度性上同使用其他几种内核对象的方法也有所不同,其他内核对象在没有得到通知时,受调用等待函数的作用,线程将会挂起,同时失去可调度性,而使用互斥的方法却可以在等待的同时仍具有可调度性,这也正是互斥对象所能完成的非常规操作之一。
  在编写程序时,互斥对象多用在对那些为多个线程所访问的内存块的保护上,可以确保任何线程在处理此内存块时都对其拥有可靠的独占访问权。下面给出的示例代码即通过互斥内核对象hMutex对共享内存快g_cArray[]进行线程的独占访问保护。下面给出实现代码清单:

代码
复制代码
// 互斥对象
HANDLE hMutex = NULL;
char g_cArray[10];
UINT ThreadProc18(LPVOID pParam)
{
 
// 等待互斥对象通知
 WaitForSingleObject(hMutex, INFINITE);
 
// 对共享资源进行写入操作
 for (int i = 0; i < 10; i++)
 {
  g_cArray[i] 
= 'a';
  Sleep(
1);
 }
 
// 释放互斥对象
 ReleaseMutex(hMutex);
 
return 0;
}
UINT ThreadProc19(LPVOID pParam)
{
 
// 等待互斥对象通知
 WaitForSingleObject(hMutex, INFINITE);
 
// 对共享资源进行写入操作
 for (int i = 0; i < 10; i++)
 {
  g_cArray[
10 - i - 1= 'b';
  Sleep(
1);
 }
 
// 释放互斥对象
 ReleaseMutex(hMutex);
 
return 0;
}
……
void CSample08View::OnMutex() 
{
 
// 创建互斥对象
 hMutex = CreateMutex(NULL, FALSE, NULL);
 
// 启动线程
 AfxBeginThread(ThreadProc18, NULL);
 AfxBeginThread(ThreadProc19, NULL);
 
// 等待计算完毕
 Sleep(300);
 
// 报告计算结果
 CString sResult = CString(g_cArray);
 AfxMessageBox(sResult);
复制代码

     互斥对象在MFC中通过CMutex类进行表述。使用CMutex类的方法非常简单,在构造CMutex类对象的同时可以指明待查询的互斥对象的名字,在构造函数返回后即可访问此互斥变量。CMutex类也是只含有构造函数这唯一的成员函数,当完成对互斥对象保护资源的访问后,可通过调用从父类CSyncObject继承的UnLock()函数完成对互斥对象的释放。CMutex类构造函数原型为:
     CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );

    该类的适用范围和实现原理与API方式创建的互斥内核对象是完全类似的,但要简洁的多,下面给出就是对前面的示例代码经CMutex类改写后的程序实现清单:

代码
复制代码
CMutex g_clsMutex(FALSE, NULL);     // MFC互斥类对象

UINT ThreadProc27(LPVOID pParam)
{
 g_clsMutex.Lock();                
// 等待互斥对象通知

 
for (int i = 0; i < 10; i++)      // 对共享资源进行写入操作
 {
  g_cArray[i] 
= 'a';
  Sleep(
1);
 }

 g_clsMutex.Unlock();              
// 释放互斥对象
 return 0;
}
UINT ThreadProc28(LPVOID pParam)
{
 g_clsMutex.Lock();

 
for (int i = 0; i < 10; i++)
 {
  g_cArray[
10 - i - 1= 'b';
  Sleep(
1);
 }

 g_clsMutex.Unlock();
 
return 0;
}
……
void CSample08View::OnMutexMfc() 
{
 AfxBeginThread(ThreadProc27, NULL);
 AfxBeginThread(ThreadProc28, NULL);

 Sleep(
300);

 CString sResult 
= CString(g_cArray);
 AfxMessageBox(sResult);
}
复制代码

posted @ 2013-01-15 10:02 盛胜 阅读(445) | 评论 (1)编辑 收藏

http://hi.baidu.com/xiao%BF%D5%BF%D5/blog/item/3c418716a6cadf12962b4344.html

CFileDialog打开当前路径

TCHAR Buffer[size];

GetCurrentDirectory(size, Buffer);

CFileDialog dlg(true,"*BIN",NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "二进制文件(*.BIN)|*.bin|All Files (*.*)|*.*|",NULL); 
dlg.m_ofn.lpstrInitialDir=Buffer;

if(dlg.DoModal())

{

//your code;

}

 

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

http://hi.baidu.com/g168999/blog/item/9ef3ab517977f1571038c2ba.html

VC获取当前程序文件的路径,文件名以及路径2种方法对比建议
2010-01-01 13:49

1.方法1

   char pBuf[MAX_PATH];                                               //存放路径的变量
   GetCurrentDirectory(MAX_PATH,pBuf);                   //获取程序的当前目录
   strcat(pBuf,"//");
   strcat(pBuf,AfxGetApp()->m_pszExeName);   
   strcat(pBuf,".exe");                                                       //获取程序的全文件名

2.方法2

   //函数返回应用程序所在的路径  

   CString    CClientApp::ReturnPath()  

   {   
   CString    sPath;   
   GetModuleFileName(NULL,sPath.GetBufferSetLength(MAX_PATH+1),MAX_PATH);   
   sPath.ReleaseBuffer    ();   
   int    nPos;   
   nPos=sPath.ReverseFind('//');   
   sPath=sPath.Left(nPos);   
   return    sPath;   
   }

3.对比及建议

方法1获取的是程序的工作路径,如某个程序安装在C,D盘或者其它任何,当你从[开始]-[程序]后的菜单中打开该文件,此时获取的是用户工作路径,如:C:/Documents and Settings/[计算机当前用户名]/....../....
如果你想通过这个路径来加载你放在程序目录下的文件,必定出错。通常这种情况在你编译调试程序时是不会出错的,你跟踪得到的绝对路径,但打包安装后一定出问题。

方法2获取的是程序的绝对路径,用这个路径加载同目录下的文件是不会有问题的。

如果你要确保成功加载文件,建议使用方法2!!!!!!


新建目录CreateDirectory

第一个参数值为文件夹名称,第二个参数值为安全属性,一般设置为NULL即可。如果正确创建,返回值为1,如果没有正常创建文件夹,则返回0。

  特别的:该函数每次调用时都只能创建一级文件夹,即文件夹中不能再包含子文件夹。
  当希望创建含有子文件夹的文件夹时,可以先使用该函数创建一级文件夹,然后再使用该函数在一级文件夹下创建子文件夹。如:
  希望创建:d:\\TEST\\temp,
  则:CString str = “d:\\TEST”;
  CreateDirectory(str, NULL);
  str = str + \\temp;
  CreateDirectory(str, NULL);

  1. CString szDir;  
  2. szDir="C:\\temp";//临时文件夹  
  3. DWORD dwAttr=GetFileAttributes(szDir);  
  4. if(dwAttr==0xFFFFFFFF)  //临时文件夹不存在则创建  
  5. {  
  6.     CreateDirectory(szDir,NULL);  
  7. )  
  8. //.........chuli  
  9. RemoveDirectory(szDir);//删除文件夹  

得到运行程序所在路径全路径(exe或其他模块文件名称,程序目录):GetModuleFileName。

函数原型:

  DWORD GetModuleFileName(
  HMODULE hModule,
  LPTSTR lpFilename,
  DWORD nSize
  );
  函数参数说明:
  hModule HMODULE 装载一个程序实例的句柄。如果该参数为NULL,该函数返回该当前应用程序全路径。
  lpFileName LPTSTR 是你存放返回的名字的内存块的指针,是一个输出参数
  nSize DWORD ,装载到缓冲区lpFileName的最大值
  函数返回值:
  如果返回为成功,将在lpFileName的缓冲区当中返回相应模块的路径,如果所设的nSize过小,那么返回仅按所设置缓冲区大小返回相应字符串内容。
  如果函数失败,返回值将为0,利用GetLastError可获得异常代码。
  需要的头文件为:

  windows.h


  
  1. #include <windows.h>  
  2.   #include <stdio.h>  
  3.   BOOL CreateSampleService()  
  4.   {  
  5.   TCHAR szPath[MAX_PATH];  
  6.   if( !GetModuleFileName( NULL, szPath, MAX_PATH ) )  
  7.   {  
  8.   printf("GetModuleFileName failed (%d)\n", GetLastError());  
  9.   return FALSE;  
  10.   }  
  11.   return TRUE;  
  12.   }  
  1. <h1><a name="t2"></a>获取程序当前路径GetCurrentDirectory(当前进程的当前路径,即程序实例目录,会随着操作的改变而改变)</h1>DWORD GetCurrentDirectory(  
  2.   DWORD nBufferLength, // size of directory buffer  
  3.   LPTSTR lpBuffer // directory buffer  
  4.   );  

  函数功能
  获取当前进程的当前目录
  参数说明
  参数 类型及说明
  nBufferLength 缓冲区的长度
  lpBuffer 指定一个预定义字串,用于装载当前目录
  返回值
  调用成功 返回装载到lpBuffer的字节数。
  如nBufferLength的长度不够,不足以容纳目录,则返回值是必要的缓冲区长度(要求至少这个长度),其中包括空中止字符。零表示失败。使用GetLastError函数可获得错误信息

CFileDialog设置打开默认路径dlg.m_ofn.lpstrInitialDir="D:\\Program File";

谨记:CFileDialog会改变程序的默认执行路径,比较稳妥的办法还是绝对路径来访问文件比较好。在程序刚一跑起来的时候,先用GetCurrentDirectory()或是GetModuleFileName()获得当前可执行文件所在的路径,并保存起来。以后即使是用CFileDialog改变了当前的路径,也能很容易地找回来。

  1. CFileDialog Dlg(TRUE,NULL,NULL,0,"ASCII Data Files(*.asc)|*.asc|所有文件 (*.*)|*.*||");  
  2.     char pBuf[MAX_PATH];                                 //存放路径的变量         
  3.       
  4.     GetCurrentDirectory(MAX_PATH,pBuf);                   //获取程序的当前目录  
  5.       
  6.     strcat(pBuf,"\\");  
  7.       
  8.     CString strtemp=pBuf;  
  9.       
  10.   
  11.     Dlg.m_ofn.lpstrInitialDir=pBuf; 

posted @ 2013-01-14 14:57 盛胜 阅读(4493) | 评论 (0)编辑 收藏

仅列出标题
共14页: 1 2 3 4 5 6 7 8 9 Last