結束了...而且我們拿到冠軍了 T__________T
從初賽爆肝寫程式
到決賽幾乎不睡覺的趕code
兩百多個class
上百頁的文件
從無到有
我覺得應該是完全發揮了我們極限了
得到這樣的成果... 我想一切的努力都是值得
這次題目初賽是一個中央監控系統
每個client都必須監控五種(或更多)系統資訊
而server會收集所有client的資訊
並且做儲存跟呈現的功能
到了決賽 更加強了server分析的功能
當某種情況符合是 則馬上出現對應措施
如最簡單的log 通知client 甚至更進一步的防範措施
我覺得這次對我門來講最難的是我們使用的是java
所以全部的功能都用jni來做
還好我們有native function大師native XD
probe部分都由他來搞定
而且強的是他都寫kernel driver..
還把兩個作業系統的版本都搞定 只能跪下來拜了
這次我們分工是這樣
我們五個人是natural(奶球) native william(葉秉哲) neil 我
natural 負責UI
native 負責probe
william 文件
neil測試 QA 安裝 使用手冊
我 網路及系統架構
還是維持兩年前的三人coding 一人QA 一人文件的分配
我覺得這樣分配很棒 也算是人盡其才 ^^
其實這次UI佔了非常大的比重
主要是我們server這邊要呈現的資料多
而且我們還有做chart跟filter的功能
所以UI絕對不是閒功夫
而我負責的是架構 其實是communication的機制 還有client probe的整合
native則是把所有的probe時做出來 然後給我包裝成共通的殼
以讓整個系統有一致性的介面
william這個寫過書的當然是文件高手囉
雖然他寫程式強 但是他是屬於慢工出細活型的..
所以讓他專心寫文件...
neil呢..則是幫我們做QA測試
並且給我們使用上的建議 讓我們可以高枕無憂的寫code..^^
到了決賽
native轉去做probe的組斷(如不能連線阿 不能開process阿.. 不能建檔阿..)
natural則是繼續他的UI 並且還有general的analysis和alert
我則是alert的架構 還有實作的部分的analysis和alert
william跟neil還是初賽的工作
我覺得我們做的很好的事情我們把功能實作的很完整
整個功能是這樣
監控
Server <------------------ Client
| ^ ------------------>
| | 控制
|--| 阻斷
分析-->警告
各方面的功能的很齊全
並且連成一迄
譬如發現四台電腦同時放進一個檔案 並且都是十秒鐘之內執行的話
我們可以通知所有電腦作組斷這個檔案產生或執行的動作
功能還不錯強大..^^
再來是我們有很不錯的測試環境
為了測試方便 可以在server通知所有client執行一個test case
在匆忙的比賽時程中 這讓我們對分散式的測試發揮最大的功效
除此之外
我們的alert也盡可能做到general
除了比賽題目訂的九個要求的alert以外
我們也根據我們自己的probe作出alert
另外還有做一個簡單的genral alert..
使用者可以根據各種probe的資訊欄位來自訂alert
並且我們設計一個generic的panel來可以設定alert的參數
若不夠 alert也可以提供自己的panel來設計alert的參數..^^
講那麼多也不知道有多少人懂
不過真的挑戰過才真的覺得自己的極限在哪
真的學到很多..
當然拿到不少錢也很高興..
可說是兩全其美..^^
不過比賽完真的還是很緊張 沒什麼信心
W怕入圍獎收場的...><
今年資科包辦了一二名
真的挺爽的
學弟真的是我出乎預料的強
感覺極度威脅到我們..><
但我想實至名歸
賽前就很主動的來問我們經驗
而且比賽完跟他們聊了一下
他們也是做的很完整
賽前也花很多時間準備
幹的好
不過感覺我們好像以老賣老
靠著高學歷來壓倒所有參賽者
不知道有沒有人感到不爽..@@"
都年紀一大把了還跟大家競爭..
不過還好沒有跌股...XD

前天跟老朋友約出來
想說聚聚聊個天
結果隨便去網路上找了一家墨西哥餐廳
在南京東路站附近 地址是復興北路202號
結果那天我從家坐捷運過去 (我家在中山國中站)
下車卻往回走了一半 早知道就走路過去了 =.=
搞不好還比較近
我點了一個巧克力烤半雞 (360) + 套餐(150)
我同學點了一個牛肉amigo(260) + 套餐(150)
都挺好吃的:D~~~
但是價錢小貴
而且可能不敢吃辣的也會吃的很痛苦
因為東西都挺辣的:D
餐廳網址在這
amigo
好久沒有寫blog囉
冷了一個月了..T_T
前一陣子比趨勢
最近又在打混
唯一有做事情的大概就是研究一下windows platform sdk吧
一個我好久沒有接觸的東西..
因為需要所以實作一個blocking queue
也就是應用producer-consumer這個pattern
沒想到java那麼簡單可以做到的事情跑到windows上就變成那麼困難
我定義了一個BlockingQueue的class
裡面有三個method
enqueue dequeue peek
enqueue是塞資料到queue
dequeue跟peek都是取資料
前者是blocking等到有資料
後者是不管有沒有都會馬上回傳
定義如下
//queue.h
#ifndef queue_h
#define queue_h
#include <windows.h>
#include <queue>
#include <assert.h>
using namespace std;
typedef struct _QueueItem{
int x;
int y;
} QueueItem;
class CBlockingQueue{
private:
queue<QueueItem> m_queue;
HANDLE m_mtx;
HANDLE m_evtAvail;
public:
CBlockingQueue();
virtual ~CBlockingQueue();
void enqueue(const QueueItem&);
BOOL dequeue(QueueItem*);
BOOL peek(QueueItem*);
};
#endif
實作的關鍵在於使用mutex跟event
mutex是一個物件 他只允許同時只能有一個thread擁有這個物件
它透過CreateMutex來產生
WaitForSingleObject或WaitForMultipleObjects來取得這個mutex
而ReleaseMutex來釋放
透過他我門能夠保證我們放入跟取出queue的動作是同時只有一個thread在執行
但是這還不夠
在producer-consumer pattern中
當consumer等不到東西時(queue size = 0)
會靜靜得等producer放東西進來的事件發生
這時候我們就要使用event這個物件
event的狀態可能是set或是unset
我門可以用SetEvent跟ResetEvent來設定他的狀態
同樣的 我門可以使用WaitForSingleObject或WaitForMultipleObjects
來等待這個event被set
所以在以下的程式裡
當enqueue放東西進來時
我門就把m_evtAvail這個event設為set
代表queue裡還有東西
而dequeue時就可以等待m_evtAvail設為set
則透過peek這個method去取得資料
值得注意的是...
在dequeue當中
當event被設為set並不保證peek一定會取得資料
因為可能在此同時也有另一個consumer也取得event被set的通知
而搶先一步去取得資料
所以我們在enqueue中有一個while loop
來保證真的取得資料時候才真正回傳
以下是這部分實作的程式碼
//queue.cpp
#include "stdafx.h"
#include "queue.h"
CBlockingQueue::CBlockingQueue(){
m_mtx = ::CreateMutex(NULL, FALSE, NULL);
assert(m_mtx != NULL);
m_evtAvail = ::CreateEvent(NULL, TRUE, FALSE, NULL);
assert(m_evtAvail != NULL);
}
CBlockingQueue::~CBlockingQueue(){
if (NULL != m_mtx)
::CloseHandle(m_mtx);
if (NULL != m_evtAvail)
::CloseHandle(m_evtAvail);
}
void CBlockingQueue::enqueue(const QueueItem& item){
DWORD dwWaitResult;
//acquire mutex
dwWaitResult = WaitForSingleObject(m_mtx, INFINITE);
m_queue.push(item);
::SetEvent(m_evtAvail);
//release mutex
ReleaseMutex(m_mtx);
}
BOOL CBlockingQueue::dequeue(QueueItem *item){
DWORD dwWaitResult;
BOOL timeout = FALSE;
BOOL done = FALSE;
while(!done && !timeout){
//printf("dequeue:wait event\n");
dwWaitResult = ::WaitForSingleObject(m_evtAvail, INFINITE);
//
switch(dwWaitResult){
case WAIT_OBJECT_0:
done = peek(item);
break;
case WAIT_TIMEOUT:
timeout = TRUE;
printf("timeout event\n");
break;
case WAIT_ABANDONED:
timeout = TRUE;
printf("abandoned event\n");
break;
default:
;
}
}
return done;
}
BOOL CBlockingQueue::peek(QueueItem *item){
DWORD dwWaitResult;
BOOL done = false;
dwWaitResult = WaitForSingleObject(m_mtx, INFINITE);
switch(dwWaitResult){
case WAIT_OBJECT_0:
if(m_queue.size() > 0){
*item = m_queue.front();
m_queue.pop();
done = TRUE;
}else{
::ResetEvent(m_evtAvail);
}
break;
case WAIT_TIMEOUT:
printf("timeout mutex\n");
break;
case WAIT_ABANDONED:
printf("abandoned mutex\n");
break;
default:
;
}
ReleaseMutex(m_mtx);
return done;
}
記得在visual studio中編譯時
把Runtime程式庫這邊改成multithread的選項(多執行緒或多執行緒偵錯)
它會把/ML(/MLd)的參數改成/MT(/MTd)
這樣一些c的library才會使用正確.. 如printf, strtok等
以下是一個範例的main
// BlockingQueue.cpp
#include "stdafx.h"
#include "queue.h"
CBlockingQueue g_queue;
DWORD WINAPI ProducerFunc(LPVOID lpParameter){
char* name = (char*)lpParameter;
QueueItem item;
for(int i=1; i<100; i++){
item.x = 0; item.y = i;
g_queue.enqueue(item);
printf("[%s](%d,%d)\n", name, item.x, item.y);
::Sleep(rand() % 1000);
}
return 0;
}
DWORD WINAPI ConsumerFunc(LPVOID lpParameter){
char* name = (char*)lpParameter;
QueueItem item;
BOOL done;
while(TRUE){
item.x = 0; item.y = 0;
done = g_queue.dequeue(&item);
//if(done){
printf("[%s](%d,%d)\n", name, item.x, item.y);
//}
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
srand( (unsigned)time( NULL ) );
//create producers
DWORD dwThreadId;
HANDLE hThread;
hThread = CreateThread(NULL, 0, ProducerFunc, "producer", 0, &dwThreadId);
hThread = CreateThread(NULL, 0, ConsumerFunc, "consumer", 0, &dwThreadId);
::Sleep(1000000000);
return 0;
}