Symbian下的线程开发模型(一)

来源:互联网 发布:淘宝网刀剑 编辑:程序博客网 时间:2024/05/16 19:21
原本想把boost里面的线程模块完全移植到Symbian S60 Fp2中,可惜内核同步的几个核心结构竟然不支持超时。没有超时概念,信号量,条件变量,以及与超时相关的锁用处就不大。同时Symbian不建议采用多线程,会加快消耗电量等等。但是AO还是有不少限制的,我还记得当初初学Windows程序设计时,把一些长任务用定时器或者用系统提供的IdleMessage进行分解的痛苦。Symbian 不建议使用线程,但不是不能使用线程,而且现在手机CPU强劲,电量都是锂电池,适量的使用线程应该没那么糟。
AO 限制:
  1:长时间的AO会导致界面阻塞,也就是说界面不刷新了。
  2:AO和按键事件在一个线程里面,也就是说AO如果长时间运行,按键事件响应将有一定时间的停滞感。
  3:AO的执行过程分解需要耗费大量的程序员心力,而且在某些时候无法确定某些代码的预测执行时间,比如网络,比如磁盘扫描等等情况将导致任务的分解是无法细化。

基于上述原因,AO并不能完全代替线程。线程的使用,将不再遇到细分任务的麻烦,使程序员的精力更多关注于逻辑而不是分解技巧。设计线程的目标是:
   1:它能和界面脱离。
   2:它是安全的,确保细节错误不重复发生。
   3:它在一个界面程序中,数量是可控制的。
   4:线程执行完毕,将资源自动归还。
   5:降低开发难度,感觉好像没用线程。

传统的开线程过程大概是这样的:
全局入口函数 :返回类型 函数名 (LPVOID pData) 
{
    对pData 转型 到原类型对象指针 pOrg;
    pOrg->.....();....
    delete pOrg;?   
}
界面响应,网络事件,电话事件.....回调处启动线程
{
      RThread curThread;
      curThread.Create( ×××××,全局构造函数,传入参数......);
}
.................
上面的代码其中有好几个地方容易犯错:
  1:线程创建函数本身,参数那么多,怎么记得住?
  2:全局函数。 每写一个线程就要搞一个线程出来。
  3:线程执行的全局函数和对象本身分离。至少,转型之后C++编译器就会阻止你访问私有成员变量和成员函数。
  4:很难控制线程的数量。导致线程过度切换,电量快速的耗费。

所以下面的线程调用方法很具诱惑:
*  class ABCDE
*  {
*         public:
*                void Fun()
*                {
*                        std::cout << "Hello stanley" << std::endl;
*                }
*         };
*          ABCDE abc;
thread trd(ABCDE::FUN, abc);

调用之后,Fun函数将在独立的线程中完成。全局函数,CreateThread,参数细节,转型,是否删除对象,完全和Client(thread类使用者无关)。(当然这还不能保证只创建唯一线程,将在下面讲述如何再次包装它。)

我把代码先贴出来,看贴的人看看是否有疑惑,如果有疑惑,我再来写详细的解释。

///简单的函数和对象绑定组件。
namespace ThreadHelper
{
        template<class T>
        class simple_bind_t
        {        
        public:
                typedef void (T::*pFn)();
                typedef pFn FunType;
                typedef T class_type;

                explicit simple_bind_t(pFn fn,T& t) : m_pFun(fn),m_t(t)
                {        
                }
                simple_bind_t(const simple_bind_t& bt) : m_pFun(bt.m_pFun),m_t(bt.m_t)
                {        
                }
                simple_bind_t<T> operator = (const simple_bind_t& r)
                {
                        m_pFun = r.m_pFun;
                        m_t = r.m_t;
                }
                FunType getfun() { return m_pFun; }
                class_type* getdata() { return &m_t;}

                void operator()()
                {        
                        return ( (m_t.*m_pFun)());
                }

        private:
                pFn m_pFun;
                T&   m_t;
        };

        template<class T>
        simple_bind_t<T> simple_bind( void (T::*fn)(), T& t)
        {
                return simple_bind_t<T>(fn,t);
        }
}

///线程组件
namespace ThreadHelper
{
        class simple
        {
        public:
                virtual void operator()()=0;
                virtual void wait() = 0;
                virtual void started() = 0;
        };

        namespace helper
        {
                template<class T>
                class thread_param : public simple
                {
                public:
                        thread_param(const ThreadHelper::simple_bind_t<T>& threadfunc)
                                : m_threadfunc(threadfunc)
                        {
                        }
                        void wait()        { }
                        void started() { }
                        void operator()()
                        {
                                m_threadfunc();
                        }

                        simple_bind_t<T> m_threadfunc;
                };
        }

        class thread
        {
        public:
                thread();

                template<class T>
                explicit thread(const simple_bind_t<T>& threadFunc,const string& name);

                ~thread();
                bool operator==(const thread& other) const;
                bool operator!=(const thread& other) const;
                void join();
                unsigned int id() const;
        private:
                static int thread_proxy(void *param);
        private:
                int m_thread;
                unsigned int m_id;
                bool m_joinable;
        };

        inline thread::thread() : m_joinable(false)
        {
                m_id = RThread().Id();
                m_thread = RThread().Handle();
        }

        template<class T>
        inline thread::thread(const simple_bind_t<T>& threadFunc,const string& name) : m_joinable(true)
        {
                helper::thread_param<T>*param = new helper::thread_param<T>(threadFunc);
                RThread curThread;
                curThread.Create( name.DesL(),
                        thread_proxy,
                        4096, 
                        NULL,
                        param);
                m_id = curThread.Id();
                m_thread = curThread.Handle();
                curThread.Resume();
        }

        inline thread::~thread()
        {
                if (m_joinable)
                {
                        RThread curThread;
                        curThread.SetHandle(m_thread);
                        curThread.Close();
                }
        }

        inline bool thread::operator==(const thread& other) const
        {
                return other.m_id == m_id;
        }

        inline bool thread::operator!=(const thread& other) const
        {
                return !operator==(other);
        }

        inline void thread::join()
        {
                if(m_joinable)
                {
                        RThread curThread;
                        curThread.SetHandle(m_thread);
                        TRequestStatus status;
                        curThread.Logon(status);
                }
                m_joinable = false;
        }
}
///一处定义到处使用的全局函数,用户不必写的。

namespace ThreadHelper
{
        void do_thread_proxy(void* param)
        {
                ThreadHelper::simple* p = static_cast<ThreadHelper::simple*>(param);
                if(p)
                {
                        (*p)();
                        delete p;
                }
        }

        int thread::thread_proxy(void* param)
        {
                CTrapCleanup* cleanupStack = CTrapCleanup::New();
                TRAPD(error,do_thread_proxy(param));
                delete cleanupStack;
                return 0;
        }
}


最终:thread trd(simple_bind(&ABCDE::FUN, abc));
当然,symbian 下使用线程和windows下面情况不同,比如你在主线程创建的一些Session 子线程没法使用,这种情况还得视系统而定。很明显,程序员还是要花费一定的心力来确保一些东西能够正确运作。我的意见是界面以及以及按键等事件的处理放到主线程处理,后台工作线程和主线程仅仅有数据的交互。也就是说,后台线程准备好数据之后,让主线程使用,主线程在接收到事件指示后发送命令给子线程。按照这样的逻辑就能够达到界面高响应的目标。

原创粉丝点击