使用线程来实现
不幸的是,没有任何编译器可以支持这两个原语,如果想使用它们,只能通过一个线程来实现,虽然会带来一些系统开销, 但是值得。为取代这两个原语,可以使用以下七个宏:
·VFLOW_EVENT_DECLARE(evt):声明一个事件变量。流程可使用事件来或发信号。
·VFLOW_EVENT_INITIALIZE(evt):初始化一个事件变量。这个宏可在C++中并入上一个宏。
·VFLOW_WAIT(evt):一个虚拟流程能调用它来等待一个事件。
·VFLOW_SIGNAL(evt):给一个事件发信号。所有等待事件的虚拟流程将会一个接一个地被激活。当被激活后,将继续之前的流程直至再碰到一个VFLOW_WAIT,此时它又被挂起,而在队列中等待的下一个虚拟流程将会被激活。调用VFLOW_SIGNAL的流程在所有等待的流程全部执行完毕后,才会继续执行。
·VFLOW_TERMINATE(evt):当它被调用时,所有等待事件的虚拟流程会立即退出。
·VFLOW_START(routine, param):要启动一个虚拟流程,需要调用routine(param)。当它遇到第一个VFLOW_WAIT时,它会将执行控制交回它的父流程。
·VFLOW_EXIT:用于虚拟流程的中途退出。
下面是修改后的代码,且在Windows与Linux下都能运行:
//analyze [scheme://[user:pass@]host[:port]]/]uri[?param[#ankor]]
#include "vflow.h" #include #include using namespace std;
class Url;
void flow_read_domain(void*); void flow_read_host(void*); void flow_read_port(void*); void flow_read_host_port(void*); void flow_read_query_string(void*); void flow_read_param(void*); void flow_read_anchor(void*);
class Url { public: Url() {} ~Url() {}
string scheme, host, port, user, pass, uri, param, anchor; string* head_token; int last_pos, cur_pos; char* url; VFLOW_EVENT_DECLARE(cur_pos_changed);
void parse_url(char* param) { VFLOW_EVENT_INITIALIZE(cur_pos_changed);
url = param; int len = strlen(url); last_pos = 0; set_pos(0); head_token = NULL;
analyze_url();
while (cur_pos < len) { set_pos(cur_pos+1); } if (head_token) *head_token = url + last_pos;
VFLOW_TERMINATE(cur_pos_changed); uri = "/" + uri; }
void set_pos(int pos) { cur_pos = pos; VFLOW_SIGNAL(cur_pos_changed); }
void analyze_url() { VFLOW_START(::flow_read_domain, this); VFLOW_START(::flow_read_query_string, this); }
void flow_read_domain() { read_to_tail(&scheme, "://");
VFLOW_START(::flow_read_host, this); VFLOW_START(::flow_read_port, this);
VFLOW_START(::flow_read_host_port, this); }
void flow_read_host() { read_to_tail(&host, "/"); }
void flow_read_port() { read_from_head(&port, ":"); }
void flow_read_host_port() { string tmp; read_from_head(&tmp, "@");
user = host; pass = port; host.erase(); port.erase();
read_from_head(&port, ":"); host = tmp; }
void flow_read_query_string() { read_from_head(&uri, "/"); VFLOW_START(::flow_read_param, this); VFLOW_START(::flow_read_anchor, this); }
void flow_read_param() { read_from_head(¶m, "?"); }
void flow_read_anchor() { read_from_head(&anchor, "#"); }
void read_to_tail(string* token, char* end_str) { head_token = token; while (1) { VFLOW_WAIT(cur_pos_changed); if (memcmp(url + cur_pos, end_str, strlen(end_str)) == 0) break; }
head_token->assign(url + last_pos, cur_pos - last_pos); last_pos = cur_pos = cur_pos + strlen(end_str); head_token = NULL; }
void read_from_head(string* token, char* start_str) { while (1) { VFLOW_WAIT(cur_pos_changed); if (memcmp(url + cur_pos, start_str, strlen(start_str)) == 0) break; } if (head_token) head_token->assign(url + last_pos, cur_pos - last_pos);
head_token = token; last_pos = cur_pos + 1; } };
void flow_read_domain(void* param) { ((Url*)param)->flow_read_domain(); } void flow_read_host(void* param) { ((Url*)param)->flow_read_host(); } void flow_read_port(void* param) { ((Url*)param)->flow_read_port(); } void flow_read_host_port(void* param) { ((Url*)param)->flow_read_host_port(); } void flow_read_query_string(void* param) { ((Url*)param)->flow_read_query_string(); } void flow_read_param(void* param) { ((Url*)param)->flow_read_param(); } void flow_read_anchor(void* param) { ((Url*)param)->flow_read_anchor(); }
int main(int argc, char* argv[]) { Url url; url.parse_url(" ghi.php?jklmn=1234&opq=567#rstuvw");
printf("schema=%snuser=%snpass=%snhost=%snport=%snuri=%s nparam=%snanchor=%sn", url.scheme.c_str(), url.user.c_str(), url.pass.c_str(), url.host.c_str(), url.port.c_str(), url.uri.c_str(), url.param.c_str(), url.anchor.c_str()); return 0; }
//vflow.h
#ifndef _VFLOW_H_ #define _VFLOW_H_
#ifdef WIN32 #include #else #include #endif
#ifdef __cplusplus extern "C" { #endif
typedef #ifdef WIN32 DWORD #else pthread_t #endif VF_THREAD_ID;
typedef void (*LPVFLOW_START_ROUTINE)(void* param);
typedef struct STRU_VIRTUAL_FLOW { VF_THREAD_ID thread_id; struct STRU_VIRTUAL_FLOW* map_prev; struct STRU_VIRTUAL_FLOW* map_next; struct STRU_VIRTUAL_FLOW* evt_next; unsigned short status; // 1 means exit #ifdef WIN32 HANDLE evt; #else pthread_mutex_t mut; pthread_cond_t cond; #endif LPVFLOW_START_ROUTINE routine; void* param; } VIRTUAL_FLOW;
typedef struct { VIRTUAL_FLOW* first; VIRTUAL_FLOW* last; } VIRTUAL_FLOW_EVENT;
//声明一个流程事件 #define VFLOW_EVENT_DECLARE(evt) VIRTUAL_FLOW_EVENT vf_##evt;
#define VFLOW_EVENT_INITIALIZE(evt) vf_##evt.first = vf_##evt.last = NULL;
#define VFLOW_START vf_start
//添加到等待队列 #define VFLOW_WAIT(evt) vf_wait(&vf_##evt);
//给等待事件的流程发信号 #define VFLOW_SIGNAL(evt) vf_signal(&vf_##evt);
//结束等待某一事件的所有流程 #define VFLOW_TERMINATE(evt) vf_terminate(&vf_##evt);
#define VFLOW_EXIT vf_exit
void vf_start(LPVFLOW_START_ROUTINE routine, void* param); void vf_wait(VIRTUAL_FLOW_EVENT* evt); void vf_signal(VIRTUAL_FLOW_EVENT* evt); void vf_terminate(VIRTUAL_FLOW_EVENT* evt); void vf_exit();
#ifdef __cplusplus } #endif
#endif // _VFLOW_H_
//vflow.c
#include "vflow.h" #include #include #ifndef WIN32 #include #include #endif
#define VF_MAP_SIZE 17
int g_vf_init = 0; VIRTUAL_FLOW* g_vf_map[VF_MAP_SIZE];
#ifdef WIN32 #define GetThreadId GetCurrentThreadId #else #define GetThreadId pthread_self #endif
//基于线程ID,从g_vf_map中获取virtual_flow //如果bCreate = 1,且它不存在,就创建一个。 //否则,如果它存在,从图中删除它。 VIRTUAL_FLOW* get_my_vf(unsigned int bCreate) { VF_THREAD_ID thread_id = GetThreadId(); int n = ((unsigned char)(thread_id >> 24) + (unsigned char)(thread_id >> 16) + (unsigned char)(thread_id >> 8) + (unsigned char)thread_id) / VF_MAP_SIZE;
VIRTUAL_FLOW** ppVF = g_vf_map + n; VIRTUAL_FLOW* pVF, *pVF2;
if (*ppVF == NULL) { if (!bCreate) return NULL;
pVF = (VIRTUAL_FLOW*)malloc(sizeof(VIRTUAL_FLOW)); pVF->map_prev = pVF->map_next = pVF->evt_next = NULL; *ppVF = pVF; } else { pVF = *ppVF; while (1) { if (pVF->thread_id == thread_id) { if (bCreate) return pVF;
if (pVF == *ppVF) { *ppVF = pVF->map_next; if (*ppVF) (*ppVF)->map_prev = NULL; } else { pVF->map_prev->map_next = pVF->map_next; if (pVF->map_next) pVF->map_next->map_prev = pVF->map_prev; } #ifdef WIN32 CloseHandle(pVF->evt); #else pthread_cond_destroy(&pVF->cond); #endif free(pVF); return NULL; }
if (pVF->map_next == NULL) break;
pVF = pVF->map_next; }
if (!bCreate) return NULL;
pVF2 = (VIRTUAL_FLOW*)malloc(sizeof(VIRTUAL_FLOW)); pVF2->map_prev = pVF; pVF2->map_next = pVF2->evt_next = NULL; pVF->map_next = pVF2; pVF = pVF2; }
pVF->thread_id = thread_id; #ifdef WIN32 pVF->evt = CreateEvent(NULL, FALSE, FALSE, NULL); #else pthread_cond_init(&pVF->cond, NULL); pthread_mutex_init(&pVF->mut, NULL); #endif pVF->status = 0;
return pVF; }
void vf_flow_wait(VIRTUAL_FLOW* vf) { #ifdef WIN32 WaitForSingleObject(vf->evt, INFINITE); #else pthread_cond_wait(&vf->cond, &vf->mut); pthread_mutex_unlock(&vf->mut); #endif if (vf->status > 0) { vf_exit(); #ifdef WIN32 ExitThread(0); #else pthread_exit(NULL); #endif } }
void vf_flow_activate(VIRTUAL_FLOW* vf) { #ifdef WIN32 SetEvent(vf->evt); #else pthread_mutex_lock(&vf->mut); pthread_cond_signal(&vf->cond); pthread_mutex_unlock(&vf->mut); #endif }
#ifdef WIN32 DWORD WINAPI #else void* #endif vf_flow_routine(void* param) { VIRTUAL_FLOW* parent_vf = (VIRTUAL_FLOW*)param; VIRTUAL_FLOW* vf = get_my_vf(1); vf->evt_next = parent_vf; parent_vf->routine(parent_vf->param);
vf_exit(); #ifdef WIN32 return 0; #else return NULL; #endif }
void vf_init() { if (g_vf_init) return;
memset(g_vf_map, 0, sizeof(g_vf_map)); g_vf_init = 1; }
void vf_start(LPVFLOW_START_ROUTINE routine, void* param) { VIRTUAL_FLOW* vf; #ifndef WIN32 pthread_t thread; #endif
vf_init();
vf = get_my_vf(1); vf->routine = routine; vf->param = param;
#ifdef WIN32 CreateThread(NULL, 0, vf_flow_routine, vf, 0, NULL); #else pthread_mutex_lock(&vf->mut); pthread_create(&thread, NULL, vf_flow_routine, vf); #endif
vf_flow_wait(vf); }
void vf_wait(VIRTUAL_FLOW_EVENT* evt) { VIRTUAL_FLOW* vf, *vf_next;
vf_init();
vf = get_my_vf(1);
if (evt->first == NULL) evt->first = evt->last = vf; else { evt->last->evt_next = vf; evt->last = vf; }
#ifndef WIN32 pthread_mutex_lock(&vf->mut); #endif
vf_next = vf->evt_next; if (vf_next) { vf->evt_next = NULL; vf_flow_activate(vf_next); }
vf_flow_wait(vf); }
void vf_signal(VIRTUAL_FLOW_EVENT* evt) { VIRTUAL_FLOW* vf, *vf_first;
vf_init();
if (!(vf_first = evt->first)) return;
vf = get_my_vf(1);
#ifndef WIN32 pthread_mutex_lock(&vf->mut); #endif
evt->last->evt_next = vf; evt->first = evt->last = NULL; vf_flow_activate(vf_first); vf_flow_wait(vf); }
void vf_terminate(VIRTUAL_FLOW_EVENT* evt) { VIRTUAL_FLOW* vf, *vf_first;
vf_init();
for (vf = evt->first; vf; vf = vf->evt_next) vf->status = 1;
vf_first = evt->first; evt->first = evt->last = NULL; if (vf_first) vf_flow_activate(vf_first); }
void vf_exit() { VIRTUAL_FLOW* vf; vf = get_my_vf(1);
if (vf->evt_next) vf_flow_activate(vf->evt_next);
get_my_vf(0); } |
|