转自:http://blog.csdn.net/arthersophy/archive/2010/04/20/5506639.aspx
线程编程在symbian os中不被鼓励使用,想来原因大家都已经知道了(线程上下文切换比活动对象开销大 等),但是对于一些特殊的需求及应用,还是需要多线程编程的,比如多媒体编程。在播放流媒体或者声音的时候,必须保证任务的连续性。
具体理论不明白的地方,请参看:Symbian c/s 机制分析
自己写了个例子,代码如下。
RThreadClien.h
public RThreadClient : public RSessionBase
{
public:
IMPORT_C RThreadClient();
IMPORT_C ~RThreadClient();
public:
IMPORT_C TInt ConnectToServer(const TDesC& aName);
IMPORT_C TInt SendReceive(TInt aFunction) const;
IMPORT_C TInt SendReceive(TInt aFunction,const TIpcArgs& aArgs) const;
IMPORT_C void SendReceive(TInt aFunction,const TIpcArgs& aArgs,TRequestStatus& aStatus) const;
private:
TVersion Version();
void DoConnectL(const TDesC& aName);
};
RThreadClient.cpp
#include "ThreadClient.h"
#include "ThreadServer.h"
const TInt KNumConnectRetries = 5;
const TInt KMaxNumberOfMessageSlots = 255;
EXPORT_C RThreadClient::RThreadClient()
{
}
EXPORT_C RThreadClient::~RThreadClient()
{
}
EXPORT_C TInt RThreadClient::ConnectToServer(const TDesC& aName) //连接到server
{
TInt ret = KErrNone;
if (Handle() == 0) // 保证一个client有一个handle.
{
TRAPD(ret, DoConnectL(aName));
if (ret != KErrNone)
{
Close();
}
}
return ret;
}
TVersion RThreadClient::Version()
{
TVersion v(1,1,1);
return v;
}
static void ThreadFunL(TAny* aData)
{
CActiveScheduler* scheduler = new (ELeave) CActiveScheduler(); //安装活动调度器
CleanupStack::PushL(scheduler);
CActiveScheduler::Install(scheduler);
CThreadServer* server = CThreadServer::NewL(); //new a custom server
CleanupStack::PushL(server);
const TDesC& name = *static_cast<const TDesC*>(aData);
server->StartL(name);
RThread::Rendezvous(KErrNone);
CActiveScheduler::Start(); //启动活动调度器
// Delete active scheduler
CleanupStack::PopAndDestroy(2, scheduler); //scheduler, engine
}
static TInt ThreadFun(TAny* aData)
{
CTrapCleanup* cleanup = CTrapCleanup::New(); //手动安装清楚栈。
TInt error = KErrNone;
if(cleanup)
{
TRAP(error, ThreadFunL(aData));
}
delete cleanup;
return error;
}
void DoLaunchThreadL(const TDesC& aThreadName, TBool aUseSemaphore)
{
TRequestStatus started, died;
RThread thread;
User::LeaveIfError(thread.Create(aThreadName, ThreadFun, 8192, NULL, const_cast<TDesC*>(&aThreadName)));//创建一个用户线程。
thread.Logon(died); // 向线程注册一下,你能够监听到线程取消或者死忘。
if (aUseSemaphore)
{
thread.Rendezvous(started); // 线程同步一种方式。不是数据交换。请求得到服务线程调用 Rendezvous(TInt) 的通知
if (started != KRequestPending)
{
thread.Kill(0); // abort startup
return;
}
}
// Logon OK - Start the epocExe
thread.Resume(); //启动线程。
if (aUseSemaphore)
{
User::WaitForRequest(started, died); // wait for start or death
if (started==KRequestPending)
{
thread.RendezvousCancel(started);
thread.Close();
User::LeaveIfError(died.Int());
}
}
thread.LogonCancel(died); //取消注册
thread.Close();
User::WaitForRequest(died);
}
void RThreadClient::DoConnectL(const TDesC& aName)
{
TInt err = KErrNone;
TInt count = 0;
TBool serverStarted = EFalse;
FOREVER
{
err = CreateSession(aName, Version(), KMaxNumberOfMessageSlots); // 创建session,session代表一个client和
// server的链接,也就是说,如果Client端调用了RSessionBase::CreateSession(),那么Server端的 NewSessionL就会被调用。猜//测下Server的实现如下:当Client端调用了RSessionBase::CreateSession (),内核找到相应的Server,然后Server线程的AS会//check这个Client在Server端有没有对应的Session,如果没有就调 用NewSessionL来创建一个Session。Client和Server后续的数据// 操作都通过这个Session来完成。 ×区别于自定义的CThreadServer ×
if (err == KErrNone) //已经存在了
{
break;
}
if ((err != KErrNotFound) || (count++ == KNumConnectRetries))
{
User::LeaveIfError(err);
}
if (!serverStarted)
{
DoLaunchThreadL(aName, ETrue);
serverStarted = ETrue;
}
}
}
EXPORT_C TInt RThreadClient::SendReceive(TInt aFunction, const TIpcArgs& aArgs) const
{
return RSessionBase::SendReceive(aFunction, aArgs);
}
EXPORT_C TInt RThreadClient::SendReceive(TInt aFunction) const
{
return RSessionBase::SendReceive(aFunction);
}
EXPORT_C void RThreadClient::SendReceive(TInt aFunction,const TIpcArgs& aArgs,TRequestStatus& aStatus) const
{
RSessionBase::SendReceive(aFunction, aArgs, aStatus);
}
CThreadServer.h
#ifndef __THREADSERVER_H__
#define __THREADSERVER_H__
#include <e32base.h>
enum TRequestType
{
EDoStart,
ECancel,
ECustomCommand,
};
// CServer2 是一个AO,从客户线程接受请求,然后把这些请求分发到相应的服务器端的客户session。它可以利用客户线程请求来创
//建服务器端的客户线程。
public CThreadServer : public CServer2
{
public:
static CThreadServer* NewL();
~CThreadServer();
void DisconectServer();
private:
// From CServer2
virtual CSession2* NewSessionL(const TVersion& aVersion,
const RMessage2 &aMessage) const;
private:
CThreadServer();
void ConstructL();
TInt SessionCount();
private:
};
#endif // __THREADSERVER_H__
CThreadServer.cpp
#include <BAUTILS.H>
#include <eikenv.h>
#include <w32std.h>
#include "ThreadServer.h"
#include "ThreadSession.h"
CThreadServer* CThreadServer::NewL()
{
CThreadServer* self = new (ELeave) CThreadServer();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CThreadServer::CThreadServer() : CServer2(CActive::EPriorityStandard)
{
}
CThreadServer::~CThreadServer()
{
}
void CThreadServer::ConstructL()
{
}
CSession2* CThreadServer::NewSessionL(const TVersion& aVersion, const RMessage2&) const
{
const TVersion v(1, 1, 1);
if (!User::QueryVersionSupported(v, aVersion))
{
User::Leave(KErrNotSupported);
}
return CThreadSession::NewL();
}
void CThreadServer::DisconectServer()
{
if (SessionCount() == 0)
{
CActiveScheduler::Stop();
}
}
TInt CThreadServer::SessionCount()
{
iSessionIter.SetToFirst();
TInt i = 0;
while (iSessionIter++)
{
++i;
}
return i;
}
//end of file
CThreadSessio.h
#ifndef PointrProtectSESSION_H_
#define PointrProtectSESSION_H_
#include <e32base.h>
#include <f32file.h>
// CSession2 服务器端的客户Session, 充当 Client和Server 的通信信道,一个Client线程能和一个Server并发多个线程。
class CThreadServer;
public CThreadSession : public CSession2
{
public:
static CThreadSession* NewL();
~CThreadSession();
public:
// From CSession2
virtual void ServiceL(const RMessage2& aMessage);
virtual void Disconnect(const RMessage2& aMessage);
private:
CThreadSession();
void ConstructL();
private:
void DoServiceL(const RMessage2& aMessage);
private:
};
#endif /*PointrProtectSESSION_H_*/
CThreadSession.cpp
#include "ThreadSession.h"
#include "ThreadServer.h"
#include "BaseWorker.h"
CThreadSession* CThreadSession::NewL()
{
CThreadSession* self = new (ELeave) CThreadSession();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CThreadSession::CThreadSession()
{
}
CThreadSession::~CThreadSession()
{
}
void CThreadSession::ConstructL()
{
}
void CThreadSession::ServiceL(const RMessage2& aMessage)
{
TRAPD(err, DoServiceL(aMessage));
if (err != KErrNone)
{
aMessage.Complete(err);
}
}
void CThreadSession::DoServiceL(const RMessage2& aMessage)
{
switch (aMessage.Function())
{
case EDoStart:
{
}
break;
case ECancel:
{
}
break;
default:
{
}
break;
}
}
void CThreadSession::Disconnect(const RMessage2& aMessage)
{
CThreadServer* server = const_cast<CThreadServer*>(static_cast<const CThreadServer* >(Server()));
CSession2::Disconnect(aMessage);
server->DisconectServer();
}