#include <ace/OS.h>
#include <ace/Task.h>
class HA_CommandHandler : public ACE_Task_Base
{
public:
virtual int svc(void)
{
ACE_DEBUG((LM_DEBUG,
ACE_TEXT("(%t) Handler Thread running/n")));
ACE_OS::sleep(4);
return 0;
}
};
int ACE_TMAIN(int, ACE_TCHAR *[])
{
ACE_DEBUG((LM_DEBUG,
ACE_TEXT("(%t) Main Thread running/n")));
HA_CommandHandler handler;
int result = handler.activate();
ACE_ASSERT(result == 0);
handler.wait();
return 0;
}
在激活線程(activate()方法)之後,主線程會調用處理器對象上的wait()方法,等待其線程完成,然後在繼續執行,並退出main()函數。
使用線程互斥體ACE_Thread_Mutex
如果成功獲得互斥體,進行獲取的線程(acquire())繼續向前執行;否則它就會阻塞,直到該互斥體的持有者釋放它(release())爲止。
#include <ace/OS.h>
#include <ace/Log_Msg.h>
#include <ace/Task.h>
#include <ace/Thread_Mutex.h>
class HA_Device_Repository
{
public:
HA_Device_Repository()
{ }
void update_device(int device_id)
{
//使用守衛
//ACE_GUARD(ACE_Thread_Mutex, mon, mutex_);
ACE_Guard<ACE_Thread_Mutex> guard(this->mutex_);
//mutex_.acquire();
ACE_DEBUG((LM_DEBUG,
ACE_TEXT("(%t) Updating device %d/n"),
device_id));
ACE_OS::sleep(1);
//mutex_.release();
}
private:
ACE_Thread_Mutex mutex_;
};
class HA_CommandHandler : public ACE_Task_Base
{
public:
enum {NUM_USES = 10};
HA_CommandHandler(HA_Device_Repository& rep) : rep_(rep)
{ }
virtual int svc(void)
{
ACE_DEBUG((LM_DEBUG,
ACE_TEXT("(%t) Handler Thread running/n")));
for (int i=0; i < NUM_USES; i++)
this->rep_.update_device(i);
return 0;
}
private:
HA_Device_Repository& rep_;
};
int ACE_TMAIN(int, ACE_TCHAR *[])
{
HA_Device_Repository rep;
HA_CommandHandler handler1(rep);
HA_CommandHandler handler2(rep);
handler1.activate();
handler2.activate();
handler1.wait();
handler2.wait();
return 0;
}
使用守衛(Using Guards)
當然你在上面的代碼中你已經看到了我已經使用了守衛(Guards)。
在許多的情況下,異常情況會在本可以完好運行的代碼中造成死鎖(忽略了某個異常路經、忘記釋放互斥體)。
守衛(Guards)基於一種常見的C++慣用手法:把構造器和析構器用於資源的獲取和釋放。
在棧上使用守衛(Guards),你就總能保證鎖的釋放,不管你的代碼所走的是什麼樣的非正常路徑。
ACE Guard Classes
Guard
Description
ACE_Guard<T>
Uses the acquire() and release() methods of lock class T during guard creation and destruction. Thus, you get the semantics of acquire() and release() methods for the specified type T.
ACE_Read_Guard<T>
Uses acquire_read() for acquisition instead of the regular acquire().
ACE_Write_Guard<T>
Uses acquire_write() for acquisition instead of the regular acquire().
ACE_TSS_Guard<T>
Allocates the guard on the heap and keeps a reference to it in thread-specific storage. This ensures that the lock is always released even if the thread exits explicitly, using ACE_Thread::exit().
ACE_TSS_Read_Guard<T>
Read version of a thread-specific guard.
ACE_TSS_Write_Guard<T>
Write version of a thread-specific guard.
當然這裏有相應的宏The following guard macros do not return values:
-
ACE_GUARD (LockType, GuardName, LockObject)
-
ACE_WRITE_GUARD (LockType, GuardName, LockObject)
-
ACE_READ_GUARD (LockType, GuardName, LockObject)
These guard macros return ReturnValue on an error:
-
ACE_GUARD_RETURN (LockType, GuardName, LockObject, ReturnValue)
-
ACE_WRITE_GUARD_RETURN (LockType, GuardName, LockObject, ReturnValue)
-
ACE_READ_GUARD_RETURN (LockType, GuardName, LockObject, ReturnValue)
任務間的通信
兩個寬泛的範疇:
1)狀態變化或事件通知;
使用條件變量ACE_Condition模板類。
獲取互斥體,檢查系統是否處在所需狀態中,所需條件爲真----如果是這樣,就執行所需操作,然後釋放互斥體,完成後更新後,調用條件變量signal()方法;所需條件爲假----調用條件變量的wait()方法,等待系統狀態發生變化。
#include <ace/OS.h>
#include <ace/Log_Msg.h>
#include <ace/Thread_Mutex.h>
#include <ace/Condition_T.h>
#include <ace/Task.h>
class HA_Device_Repository
{
private:
ACE_Task_Base* owner_;
//ACE_Thread_Mutex mutex_;
public:
HA_Device_Repository() : owner_(0)
{ }
void update_device(int device_id)
{
////使用守衛
//ACE_Guard<ACE_Thread_Mutex> guard(this->mutex_);
ACE_DEBUG((LM_DEBUG,
ACE_TEXT("(%t) Updating device %d/n"),
device_id));
ACE_OS::sleep(1);
}
int is_free(void)
{
return (this->owner_ == 0);
}
int is_owner (ACE_Task_Base* tb)
{
return (this->owner_ == tb);
}
ACE_Task_Base* get_owner(void)
{
return this->owner_;
}
void set_owner(ACE_Task_Base* owner)
{
this->owner_ = owner;
}
};
class HA_CommandHandler : public ACE_Task_Base
{
private:
HA_Device_Repository& rep_;
ACE_Thread_Mutex& mutex_;
ACE_Condition<ACE_Thread_Mutex>& waitCond_;
public:
enum {NUM_USES = 10};
HA_CommandHandler(HA_Device_Repository& rep,
ACE_Condition<ACE_Thread_Mutex>& wait,
ACE_Thread_Mutex& rep_mutex)
: rep_(rep),
waitCond_(wait),
mutex_(rep_mutex)
{ }
virtual int svc(void)
{
ACE_DEBUG((LM_DEBUG,
ACE_TEXT("(%t) Handler Thread running/n")));
for (int i=0; i < NUM_USES; i++)
{
this->mutex_.acquire();
while (!this->rep_.is_free())
//阻塞,進入休眠
this->waitCond_.wait();
this->rep_.set_owner(this);
this->mutex_.release();
this->rep_.update_device(i);
ACE_ASSERT(this->rep_.is_owner(this));
this->rep_.set_owner(0);
//讓阻塞的進程甦醒過來
this->waitCond_.signal();
//讓甦醒過來的進程有機會獲得條件變量
ACE_OS::sleep(1);
}
return 0;
}
};
int ACE_TMAIN(int, ACE_TCHAR *[])
{
HA_Device_Repository rep;
ACE_Thread_Mutex rep_mutex;
ACE_Condition<ACE_Thread_Mutex> wait(rep_mutex);
HA_CommandHandler handler1(rep, wait, rep_mutex);
HA_CommandHandler handler2(rep, wait, rep_mutex);
handler1.activate();
handler2.activate();
handler1.wait();
handler2.wait();
return 0;
}
2)消息(數據)傳遞(Message Passing)。
消息塊(Message Blocks)
ACE_Message_Block 一種高效的數據容器,可以用來高效的存儲和共享消息。支持引用計數和數據共享特性。
rd_ptr()指針,指向要讀取的下一個字節,;
wr_prt()指針,指向下一個可用的空字節;
copy()方法把數據複製到消息塊;
msg_type()修改類型字段。
一旦你使用完了消息塊,要用release()方法釋放它,使引用計數減一,當引用計數到達0時,ACE會自動釋放這個塊分配的內存。
使用消息隊列ACE_Message_Block
ACE_Task模板類含有一個ACE_Message_Block,你可以傳入模板參數,ACE_MT_USE,讓ACE_Message_Block是多線程安全的FIFO。
ACE_Task::putq()消息塊入隊;
ACE_Task::getq()消息塊出隊。
這裏有多種ACE_Message_Block子類,有不同的特徵:
Name
Description
ACE_Dynamic_Message_Queue
A priority-queue implementation that dynamically readjusts the priority of a message, using variants of the earliest-deadline-first scheme and a laxity (time to deadline minus worst-case execution time) schemes. For details, see the ACE reference documentation.
ACE_Message_Queue_Vx
Wrapper around the Wind River VxWorks message queue facility.
ACE_Message_Queue_Ex
An even more type-safe version of ACE_Message_Queue.
ACE_Message_Queue_NT
Implementation that is built on Windows NT's I/O completion port features.[a]