1.模式介绍
角色:多个竞赛者,一个裁判
动机:多个竞赛者进行同样的事情(竞赛项目),选出最早完成的参赛者。
实现:
.支持排名和选拔两种赛制
.隐式裁判
.选拔不支持多选(只支持选择最快的)
应用:
.本地服务器直接连接时,如果托管服务器有2个ISP,则访问者可以从这2个ISP选择一个较快的网络连接。
.可应用于并行应用情形,如加载托管机构证书时利用此模式可提高启动速度
2.实现
typedef int (*GAME_TASK_FUNC)(void *arg); ///< 比赛任务函数
class CGame;
class CPlayer {
friend class CGame;
friend DWORD WINAPI player_entry_func(void *arg);
CGame *game_;
int i_id_; ///< 内部编号
void *arg_; ///< 任务函数参数
HANDLE fini_signal_; ///< 任务完成信号
HANDLE thr_handle_; ///< 线程句柄
int result_; ///< 任务执行结果
int rank_;///< 名次: 0-无名次
int run();///< 比赛开始
public:
CPlayer(void *arg);
~CPlayer();
CGame* get_game() { return game_; }
///< 参加比赛
void join(CGame *game) { game_ = game; }
///< 预备
int ready();
///< (中途)结束
void exit();
///< 比赛完成
void notify_fini(); ///< 比赛完成通知
int get_iid() const { return i_id_; }
int get_rank() const { return rank_; }
void* get_arg() const { return arg_; }
};
/// 竞赛项目
class CGame {
friend class CPlayer;
friend DWORD WINAPI player_entry_func(void *arg);
public:
enum GAME_TYPE { GT_RANKD=1,GT_CTB}; ///< 比赛类型:排名,选拔
private:
GAME_TASK_FUNC task_func_;///< 比赛项目任务
HANDLE signal_; ///< 发令(比赛开始信号)
int type_; ///< 1-排名(所有选手完成的顺序) 2-选拔(选择最快的一个)
vector<CPlayer*> players_;
int rank_count_; ///< 当前名次
CRITICAL_SECTION lock_; ///< rank_count_锁
void rank(int iid); ///< 某个选手完成项目后定名次
public:
CGame();
virtual ~CGame();
void set_type(int type) { type_ = type;}
void set_task(GAME_TASK_FUNC fp) { task_func_ = fp; }
void add_player(CPlayer *player); ///< 加入选手
size_t get_player_num() const { return players_.size();}
CPlayer* get_player(size_t index) { return players_[index];}
int start(); ///< 比赛开始
void report(); ///< 报告比赛结果
CPlayer* find(int rank,int result); ///< 查询名次
};
template <class T> int HoldGame(short game_type,GAME_TASK_FUNC fp,T *player_info,size_t player_num) {
CGame *game = new CGame;
game->set_type(game_type);
game->set_task(fp);
for (int i=0;i<player_num;i++) {
T *playinfo = &player_info[i];
CPlayer *player = new CPlayer(playinfo);
game->add_player(player);
}
game->start();
CPlayer *winner = game->find(1,0);
int winner_index = winner==0 ? -1 : winner->get_iid();
delete game;
return winner_index;
}
3.应用示例
以下示例应用竞赛模式在多ISP时选择网络。
.TestNetSpeed是竞赛任务函数:执行连接,发送消息并获取一个响应消息
.TestSpeed是实现多ISP选择的执行函数
#include "compete.h"
using namespace sens;
int TestNetSpeed(void *arg) {
SvcEntry *entry = (SvcEntry*)arg;
const char *bind_addr = CAPPlugin::instance()->central_server_.sw_bind_ip_.empty() ? 0 : CAPPlugin::instance()->central_server_.sw_bind_ip_.c_str();
SOCKET handle = Connect(entry,bind_addr);
if (handle==INVALID_SOCKET)
return -1;
CMsg *req = new CMsg;
req->SetMsgType(MT_REQUEST);
req->SetMsgID(312);
req->AddParam("bp",(long)clock());
if (Send(handle,req)) {
return -1;
}
CMsg *ans = 0;
if (Recv(handle,&ans)) {
return -2;
}
ans->Release();
return 0;
}
int TestSpeed(SvcEntry *entry_list,short entry_num) {
return HoldGame<SvcEntry>(2,TestNetSpped,entry_list,entry_num);
}