设为首页收藏本站Access中国

Office中国论坛/Access中国论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

返回列表 发新帖
楼主: 李寻欢
打印 上一主题 下一主题

请高手帮忙

[复制链接]
11#
发表于 2002-12-19 23:30:00 | 只看该作者

1

让程序自动管理线程的代码
引言
多线程是一种很好的程序机制,使用线程可以充分的利用电脑资源,进行并行的业务处理。不过好的东西总有它的不足。线程是好,不过滥用,或管理不当就会造成线程混乱,内存漏洞,造成电脑速度变慢,反应迟钝。

想法
于是有人提出能不能让线程自己管理自己,把这复杂的工作交给电脑来处理。笔者经过多年的实践,终于用VC++实现了这一目的。
大家知道在VC++中我们可以用CreateThread创建一个线程,该函数返回这线程的Handle,以后我们就可以用这个Handle来管理这个线程的。于是我们可以做一个类名为ThreadManager,来管理这些Handle,并随时监控这些线程的状态。
总的思想就是这样,不过为了方便使用,我们最好把这个类封装成DLL的形式,这样以后我们在任何程序中都可以很方便的用该类来管理线程了(当然如果你有兴趣,也可以用COM模型来实现)。

实现
因为我们要把一切工作全交给ThreadManager,所以线程的创建,监控,删除都将在该类中实现,而我们仅要做的就是把线程函数名和线程参数传给ThreadManager类,于是我们定义该类构造函数为:

ThreadManager(ThreadPrc threadpro,LPVOID pParam);
该类还要能启动线程,于是我们又定义一个启动函数: RunThread();
另外我们有时还要能获得线程的Handle,于是又定义一个函数: HANDLE GetThreadHandle();
而该类唯一的成员参数就是Handle: HANDLE m_Handle;
于是ThreadManager定义如下: typedef DWORD (WINAPI *ThreadPro)(LPVOID);
class  CThreadManager : public CObject
{
        DECLARE_DYNAMIC( CThreadManager ) 
public:
        CThreadManager( ThreadPrc threadpro, LPVOID pParam);
        ~CThreadManager();
        CBOOL RunThread();
        HANDLE GetThreadHandle() const { return( m_Handle ); };  
private:
        HANDLE m_Handle;
};
显然,我们仅有这一个类还不能完成我们所需的工作,我们还要一个负责具体监控的ThreadTask类,ThreadTask类中有一个监控线程ThreadTaskFunc( )负责监控并删除线程。该类定义如下: class CThreadTask : public CObject
{
DECLARE_DYNAMIC( CThreadTask )
public:
        CThreadTask();  //构造函数
        ~CThreadTask();
        CBOOL IsValid();  
        void AddHandle( CONST HANDLE cHandle );  //添加线程句柄到m_ObList中
         
        void CloseThreadHandles();    //(关闭线程)
        static CThreadTask& GetCThreadTask();    //用于在Managerthread类中获得ThreadTask类的指针

        CObList        m_ObList;//线程句柄组
        HANDLE m_Handle;//线程句柄
         
        BOOL m_bKeepGoing;//是否已运行
};

IMPLEMENT_DYNAMIC( CThreadCareTaker, CObject )
其中IsValid()是用于检验ThreadTaskFunc()是否已动行了,其它意思都很明显。

流程图
总的流程图如下:


具体实现
下面给出它的具体实现。


ThreadTask::ThreadTask()
{
  m_bKeepGoing = TRUE;
  //表示已运行
  DWORD nThreadId = 0;
  //创建管理线程
  m_Handle = (HANDLE)::CreateThread(NULL,0,ThreadTaskpro,0,0,&nThreadId );
}
void ThreadTask::AddHandle( CONST HANDLE cHandle )
{
        CHandle *pHandle = new CHandle;
        pHandle->m_ThreadHandle = cHandle;
        m_ObList.AddTail( pHandle );
         
}
void ThreadTask::CloseThreadHandles()
{
        if ( m_ObList.GetCount() )
        {
                POSITION pos1, pos2;
                CHandle *pHandle = (CHandle *)NULL;  
                //(CHandle类相当简单,只有一个成员函数m_ThreadHandle)
                DWORD dwExitCode = 0L;
                for( pos1=m_ObList.GetHeadPosition(); (pos2=pos1)!=POSITION(NULL); )
                {
                        //历遍所有已有的线程句柄
                        pHandle = DYNAMIC_DOWNCAST( CHandle, m_ObList.GetNext( pos1 ) );
                        //获得第pos1个handle
                        VERIFY( ::GetExitCodeThread( pHandle->m_ThreadHandle, &dwExitCode ) );
                        //获得线程pHandle的当前状态
                        if ( dwExitCode != STILL_ACTIVE )
                        //如果已完成
                        {
                                //释放当前句柄
                                m_ObList.RemoveAt( pos2 );         
                 
                                VERIFY( ::CloseHandle( pHandle->m_ThreadHandle ) );
                                delete pHandle;
                                pHandle = (CHandle *)NULL;
                        }
                }
        }
}

ThreadTask::~ThreadTask()
{

}

ThreadTask & ThreadTask::GetThreadTask()
{
        //返回静态ThreadTask对象,以便ThreadManager类调用
        static ThreadTask  Taker;
        return(Taker);
}

BOOL ThreadTask::IsValid()
{
        //是否已运行
        BOOL bValid_Status = FALSE;
        if ( (this != NULL) && AfxIsValidAddress( this, sizeof( ThreadTask ) ) )
                bValid_Status = TRUE;
        return( bValid_Status );
}

下面介绍线程ThreadTaskpro(); 该线程最主要的目的就是调用ThreadTask的CloseThreadHandles()函数,实现如下: DWORD WINAPI ThreadTaskpro( LPVOID pParam  )
{

        HANDLE hCurrentThread = GetCurrentThread();
        //
12#
发表于 2002-12-19 23:38:00 | 只看该作者

1

哈哈哈!!找到了!!使用DAO可以解决!!



    DAO itself is not multithreaded, so you can't use the MFC DAO classes in multiple threads. Confine your DAO code to a single thread of execution. Otherwise, look for some other thread-safe database operations.
    More ideas regarding this question.
    As MFC document stated, the DAO classes are not thread safe. I thought probably finish the coding of your application and have tons of code there already, and don't have enough time to change to another database
    classes. So you really want to use DAO in your multi-thread application, there is a solution for you.
    And you should remember that this is not a true multithread database access, the Jet will serialize the database function calls. In order to operate the database using DAO in different threads, you have to create its own CDaoDatabase and CDaoRecordset instance in each thread.
    1. declare a global instance of critical section
     CCriticalSection g_CS;
    2. In your thread function
     // prevent multi-threads initialize the DAO simultaneously
     // it will be unlocked when out of scope
     CSingleLock lock(&g_CS, TRUE);
     // initialize DAO support of MFC
     AfxDaoInit();
     // initialize your Dao classes here
     CDaoDatabase db;
     CMyDaoRecordset rs( &db );
     // Open the database and recordset
     .....
     lock.Unlock(); // free lock to let other threads use Dao
     ///////////////////////////////////////////
     // your database operation goes here
     // when you doing this, you don't have to lock other threads
     .............................
     ///////////////////////////////////////////
     // After you finish the database operation
     // lock again and close your recordset and database
     lock.Lock();
     rs.Close();
     db.Close();
     return;
    3. In your CApp::ExitInstance(), add these two lines
     AfxDaoInit();
     AfxDaoTerm();
    Hope this will help you.

点击这里给我发消息

13#
发表于 2002-12-20 21:02:00 | 只看该作者
解决了吗?
14#
发表于 2002-12-21 11:29:00 | 只看该作者
斑竹老是把C语言的东西高上来。
用WINSOCK做二进制传送可以用字节数组,读取文件应该没有问题,当然是一次把文件度出来,对现在的机器来说,发送应该也不会慢。你不是向服务器发送吗?为何不试试INTERNET控件,用FTP不是更方便吗?
15#
 楼主| 发表于 2002-12-21 17:17:00 | 只看该作者

文件读取已搞定

行家一伸手,就知有没有。
txman兄的一番话,讲得非常有道理,您好象对VB很熟?以后还请多多指教。
二进制读取已做成功了,真的可以读写任意文件,而不仅仅是文本文件,就是用字节数组来读写文件,在本地做得到,当然也可以传送了。源程序在下面:
http://klhome.vicp.net:5700/cdb/viewthread.php?tid=623&sid=b3283d98732d6e3729fdc6bfb868247a
16#
发表于 2002-12-21 18:30:00 | 只看该作者
但如果用这种方式来传送文件,那不是太慢了吗?谁有解决方法?请帮我一把!

-----------------------------------------------------------------------

老兄,你的问题好像根本没有解决啊?用byte复制文件的方法谁都知道(长二进制存储文件到ole字段里面就用的同样方法),但是太慢和断线后无法接着传的毛病一直没有人解决。
17#
 楼主| 发表于 2002-12-21 18:50:00 | 只看该作者
用字节数组就不慢了,数组的大小可以根据网络状况来定,因我以前没想到用数组,只是字节类型,所以我原来说一个字节一个字节地传送太慢了,而用数组的话,可以把文件分成一块一块地传,这样就快多了。
用字节的方式来读文件,断点续传就不是什么大问题了。远程连接的突然断开会触发一些事件,在这些事件里记录已传送的字节数,下一次再从已传送的下一个字节读取就行了。
18#
发表于 2002-12-21 19:02:00 | 只看该作者
奥?请问你的所说的复制是以文件共享方式完成的?
不是以http协议或者ftp协议完成的?
19#
 楼主| 发表于 2002-12-21 19:21:00 | 只看该作者
不是很明白您所说的意思。
文件从一部电脑传送到另一部电脑,其实也是一个复制的过程,这个过程是这样的:
先从传送端读取文件块,通过TCP(远程)或UDP(局域网)协议传送到接受端,直到所有的文件块传送完毕。
20#
发表于 2002-12-21 19:28:00 | 只看该作者
比如说我有一个向www.etang.com申请的免费ftp空间和主页存放空间,能否用你的方法传送文件过去?

不行吧?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|站长邮箱|小黑屋|手机版|Office中国/Access中国 ( 粤ICP备10043721号-1 )  

GMT+8, 2024-11-25 20:48 , Processed in 0.102215 second(s), 31 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表