re: CEnumClass—类型安全的枚举类型 Kevin Lynx 2008-08-13 10:05
我觉得,用你这个类与普通的enum相比,更多时候我们需要的是一个方便的enum,即使它没有你这个class安全;
如果我没弄错的话,你这个类虽然sizeof为sizeof(int),但这并不是你所说的“同时也没有占用任何额外的空间”,因为还有很多static常量。
@陈梓瀚(vczh)
就我所查阅的文档来看,似乎没有。coroutine.yiled/resume可能算是吧。
re: 自己写的一个GUI框架的消息机制 Kevin Lynx 2008-08-07 09:17
@eXile
我亦觉得,楼主局限于native win32的思维方式。在对消息的处理上,遵从的是WIN32的消息机制。
不过从代码看来(LRESULT之类),这个框架可能没有考虑跨平台特性。所以停留在WINDOWS上也没什么。
个人拙见。:)
re: 建立异步操作组件:队列和线程 Kevin Lynx 2008-08-06 13:11
@francis
thread2没有获得CPU权!thread2没有被调度!
这里的用法完全是条件变量的标准用法,如果你硬是要从理论上认为它有问题,那你可以去查条件变量相关资料。这里的结构和条件变量通用用法一样。你甚至可以找本操作系统书,在上面找到条件变量的使用结构。你想推翻这一切?建议你大量查阅条件变量相关资料。如果你还认为有问题,你应该去对发明条件变量的某个可能已经死掉的牛人说:你这个条件变量的结构有问题。
re: 建立异步操作组件:队列和线程 Kevin Lynx 2008-08-06 09:07
@francis
我读了几遍你的这次回复,希望我没有误解你的意思:
thread1被激活,取数据,就可能导致container的size为0,一旦size为0,thread3继续push的时候就可能会激活thread2。如果OS一直没有调度到thread2,那么,container就可能经历过多次size为0,size不为0,也就是thread1和thread3发生多次数据交互。thread2看起来是惨了,因为container曾经有数据,但是thread2却没取到?为什么呢?thread2根本没被OS调度到,从没有获取到CPU控制权,它又有什么理由不wait?
归根结底,你说的这个问题,只是因为thread2没有被调度到而已。
re: 建立异步操作组件:队列和线程 Kevin Lynx 2008-08-05 09:00
@francis
详述下这种会出现问题的情况。如果可以模拟出现的话,麻烦基于multi_list这个类制造这种情况。
re: 建立异步操作组件:队列和线程 Kevin Lynx 2008-08-04 22:28
@francis
while( _container.size() == 0 ) _condition.wait();
仅当为空的情况下才wait的。代码在逻辑上不存在大问题,因为这个基础部件已经被用于实际项目(用于保存验证服务器端的验证帐号)。
re: 建立异步操作组件:队列和线程 Kevin Lynx 2008-08-04 16:43
@francis
我们看一次常规的同步操作:
push_front()
{
guard<mutex_type> g(_mutex );
...
}
pop_front()
{
guadr<mutex_type> g(_mutex );
...
}
那么,在消费者线程里可能会不断地去检查队列大小是否为0(size操作同样会涉及到同步),
这浪费了CPU资源。而如果:
pop_front()
{
guadr<mutex_type> g(_mutex );
while( size == 0 ) _cond.wait();
}
当大小为0时,wait操作将阻塞此线程,从而让出了CPU资源(wait会阻塞)。
另一方面,如果每次push操作都进行条件变量的signal,这个所谓的原语操作开销有多大?
查看condition::signal/wait代码,其内部还存在一个_wait_count的同步。另外,如果
每次push都signal的话,那么pop操作也需要进行wait,这样以来它其实已经不是条件变量,
而是信号量了。
我们所要的效果,就是在队列元素为0时,进行pop操作的时候让其阻塞而已。
re: 建立异步操作组件:队列和线程 Kevin Lynx 2008-08-04 12:55
@francis
关键在于,signal和wait会对外部mutex做操作。参见kl_condition.h相关代码。
re: 建立异步操作组件:队列和线程 Kevin Lynx 2008-08-03 10:40
@francis
你可以查找‘条件变量’(condition variable)的相关资料。
signal只在队列尺寸为0时的push操作中调用,因为在pop中会在队列尺寸为0时wait.
re: 实现自己的http server Kevin Lynx 2008-08-01 16:08
@Strive
很巧, 我恰好看过这个网站,感觉是个少年天才的主页。之前搜索QQ协议,发现的。还下了他写的QQ客户端,不过有问题,我登陆Q后,就被T了。
re: 实现自己的http server Kevin Lynx 2008-07-31 08:56
@zx
高并发数不见得要使用async(不明白你所谓的Async模式是什么?我假设是异步IO),也不见得要使用Overlapped IO (我也不明白你说的"IO的overlapped",我假设是windows下的Overlapped IO),一个event-driven的网路模型就很不错了。
@x-matrix
本文的重点在于对HTTP协议的解析,而不是开发高并发网络框架。:)
re: GP技术的展望——先有鸿钧后有天 Kevin Lynx 2008-07-26 22:33
longshanks终于又发文了。学习。
@happyday
取元素只是从树根取,取了后需要对整棵树进行调整。
插入元素插入到最下最右的节点,插入后需要进行微小的调整。
总之元素的增加/减少,都需要重新调整整棵树使其依然为一个堆。
re: 日志该怎么记录? Kevin Lynx 2008-07-18 10:48
越来越写得水了。
@true
那就应该没问题了。‘应用程序初始化失败’,你用的是VS2005吧?那就跟BOOST没关系了。新的问题跟项目设定有关系。具体搜索下网络吧。:)
我以前编译ASIO例子程序的时候,就显示地忽略了以下两个库:
libboost_date_time-vc80-mt-gd-1_34_1.lib
libboost_regex-vc80-mt-gd-1_34_1.lib
但是,libboost_system-vc80-mt-gd-1_35.lib则没遇到过,你显示地忽略掉看下如何?
re: VS2005编译libevent Kevin Lynx 2008-07-07 12:53
libevent在windows下似乎没多大实用价值(因为用的是select)。spserver的作者写了个IOCP版本。
貌似是有这样的现象,例如libevent的VC6工程文件用RAR解开后就是坏的。
re: GameRes里面某位大师的语录 Kevin Lynx 2008-06-26 21:51
‘游戏之家站长’的故事源远流长。。。
偶然发现LZ博客有我以前CSDN的链接,呵呵,现在我换到CPPBLOG来了,更新下链接吧。
re: 建立异步操作组件:队列和线程[未登录] Kevin Lynx 2008-06-26 09:14
@饭中淹
前面我说了,condition和guard使用的是同一个mutex,在condition的wait里,会先_external_mutex.release();,然后push的时候,就不会阻塞在guard那里,于是condition.signal(元素为0时,看下代码),然后pop里的condition.wait就过了。
re: 建立异步操作组件:队列和线程 Kevin Lynx 2008-06-25 21:42
@饭中淹
不会的,condition和guard使用的都是同一个mutex。guard用于一般的同步,condition用于队列元素为0时的临界条件。
re: 为什么很多人喜欢在代码中写错别字呢[未登录] Kevin Lynx 2008-06-25 17:13
@true
事实上是我写的. :D 我写着玩,但是被用到我们的产品里。
re: 为什么很多人喜欢在代码中写错别字呢[未登录] Kevin Lynx 2008-06-25 16:41
比较有意思的:
/// my fucking and ugly sorted queue only for ServerInfo struct, because i want
/// everytime i push_back an element in the queue, it will update the element
/// which _ls_id && _ws_id && _gs_id already existes.I adapted this queue so that
/// it can be used in my multi_list. :D I'm a such programmer
template <typename _Tp, typename _AllocType = std::allocator<_Tp> >
class my_fucking_list;
/// partial version for ServerInfo
template <typename _AllocType>
class my_fucking_list<ServerInfo, _AllocType>
{
public:
re: 建立异步操作组件:队列和线程[未登录] Kevin Lynx 2008-06-25 16:22
@true
貌似你误解我意思了;)
’阻塞时不能退出‘:
例如线程里 WaitFor...INFINITE了,那么它就无法处理消息,也无法判断退出标志变量,代码卡在这里了。
’他更及时,不用参与排队‘:
这个跟上面不是说的同一个问题,队列是用于实际业务处理,例如写日志,上面那个说的是线程。
re: 从wave文件的读写看程序中struct的设计 Kevin Lynx 2008-06-16 11:21
有道理,对于用struct写文件这种情况,很容易因为struct的字节对齐问题导致想不到的BUG。尤其是采用直接将struct以二进制方式写入文件的方式写文件。
re: SGI STL的内存池 Kevin Lynx 2008-06-15 09:40
@Gohan
rebind可以让allocator<Tp>的保存者分配其他类型的内存。例如,当实例化list时(例如list<int,my_allocator<int> > ),在list内部就保存着一个my_allocator<int>,但是list需要为自己分配list_node,就是说它需要另一个allocator,那么这个时候就可以通过rebind来完成。
re: SGI STL的内存池 Kevin Lynx 2008-06-13 12:36
@关中刀客
STL默认那个内存池。。。STL默认没内存池。SGI的STL里那个内存池不是标准的。VC下的STL就没这个。
re: (C++)一个愚蠢的错误 Kevin Lynx 2008-06-07 09:27
错误就是 memset( ...string ) ?
有点巧,我同事也犯过这个错。:D
@关中刀客
难道不开源?不知道能否分享下代码。
我之前在google,baidu都搜索过你这个东西,没有发现类似googlecode之类的项目地址。。
re: IRR的效果图 Kevin Lynx 2008-06-06 16:21
@true
这些是irrlicht引擎的DEMO图
@关中刀客
传说哥们和我同年同月差一天就同日生(我10号:d)
还有,一直想看下你的cobra是个什么东西
re: 写了个简单的聊天服务器 Kevin Lynx 2008-06-06 10:59
@jigloo
"网络层用reactor模式封装异步IO" 似乎proactor才是用于封装异步IO的吧?
关于你提出的这几层封装,不知道是否可以提供个简单的整体类图?不甚感激。
re: 【原创】系统设计之 必备外围功能-log Kevin Lynx 2008-06-05 17:50
日志对于一个系统来说确实是必不可少的基础模块。
我用模板写了个不依赖于具体‘写’的日志类,简单的日志等级过滤。
///
/// @file kl_logger.h
/// @author Kevin Lynx
/// @date 4.21.2008
///
#ifndef ___KL_LOGGER_H_
#define ___KL_LOGGER_H_
#include <assert.h>
#include <stdarg.h>
#include <time.h>
#include <fstream>
#include "kl_compiler_cfg.h"
KL_COMMON_NAMESPACE_BEGIN
/// log level
enum log_level
{
LL_MIN = -1,
LL_ERROR,
LL_WARNING,
LL_INFO,
LL_DEBUG,
LL_MAX
};
///
/// default log pre-string, add system time and log level.
///
struct default_log_prestr
{
/// output pre-string in the buffer
/// @return the offset of the buf.
std::size_t operator() ( char *buf, int level )
{
char time[9];
char date[9];
_strtime( time );
_strdate( date );
const char *ll_desc = 0;
switch( level )
{
case LL_ERROR:
ll_desc = "ERROR";
break;
case LL_WARNING:
ll_desc = "WARNING";
break;
case LL_INFO:
ll_desc = "INFO";
break;
case LL_DEBUG:
ll_desc = "DEBUG";
break;
default:
ll_desc = "UNKNOWN";
}
// combine
sprintf( buf, "%s %s %s : ", date, time, ll_desc );
return strlen( buf ) ;
}
};
///
///
/// A simple logger class to write log information.
///
/// @param _Output where the log information to put, it must implement 'log( const char*)' function.
/// @param _PreStr used to write the pre-string of the log text like : 4.21.2008 : something.
/// @param string_size used when format string.(static buffer is more fast than dynamic buffer)
template <typename _Output, typename _PreStr = default_log_prestr, std::size_t _string_size = 1024>
class logger
{
public:
/// output object type
typedef _Output output_type;
/// pre-string type
typedef _PreStr prestr_type;
/// string size used when formatting strings.
enum
{
string_size = _string_size
};
public:
/// constructor
logger() :
_output( 0 ), _level( LL_DEBUG )
{
}
/// destructor
~logger()
{
}
/// set the output manager, you must call this function before you
/// log anything.
void set_output( output_type *ot )
{
assert( ot != 0 && "logger::set_output : invalid arguments." );
_output = ot;
}
/// write log text
void write_only( int level, const char *format, ... )
{
assert( _output != 0 && "logger::write_only : You must set up the output manager before you log anything." );
static char buf[string_size];
// checck the level
if( level > _level ) return ;
// format the string
va_list list;
va_start( list, format );
vsprintf( buf, format, list );
va_end( list );
// output the log text
_output->log( buf );
}
/// write log text and append prestring
void write( int level, const char *format, ... )
{
assert( _output != 0 && "logger::write : You must set up the output manager before you log anything." );
static char buf[string_size];
// checck the level
if( level > _level ) return ;
// append pre-string
std::size_t pos = _prestr( buf, level );
// format the string
va_list list;
va_start( list, format );
vsprintf( &buf[pos], format, list );
va_end( list );
// output the log text
_output->log( buf );
}
/// set log level
void set_level( int level )
{
assert( level > LL_MIN && level < LL_MAX && "logger::set_level : invalid arguments." );
_level = level;
}
/// get the log level
int get_level()
{
return _level;
}
private:
/// output manager to collect log text.
output_type *_output;
/// pre-str to append some text before the log text
prestr_type _prestr;
/// log level
int _level;
};
///
/// The file log output manager, write log text to the file.
///
class file_output
{
public:
/// constructor
file_output()
{
}
/// this constructor will open the file
file_output( const std::string filename, std::ios_base::openmode _Mode = std::ios_base::out ) :
_file_handle( filename.c_str(), _Mode )
{
}
/// destructor
~file_output()
{
}
/// open the file if it's not open
bool open( const std::string filename, std::ios_base::openmode _Mode = std::ios_base::out )
{
if( _file_handle.is_open() )
{
return false;
}
_file_handle.open( filename.c_str(), _Mode );
return _file_handle.is_open();
}
/// log
void log( const char *str )
{
assert( _file_handle.is_open() && "file_output::log : you cannot write anything before you open the file!" );
_file_handle << str ;
_file_handle.flush();
}
private:
/// output file
std::ofstream _file_handle;
};
KL_COMMON_NAMESPACE_END
#endif // end ___KL_LOGGER_H_
貌似console下也可以调用GetAsyncKeyState
re: 突破select的FD_SETSIZE限制 Kevin Lynx 2008-05-20 14:24
@eXile
谢谢提醒,win_fd_set_adapter.hpp确实是个方案。那估计是用__WSAFDIsSet也不是问题了。:)
re: 突破select的FD_SETSIZE限制 Kevin Lynx 2008-05-20 13:03
@2nd guest
我觉得这个东西不复杂,只要保持模块对外接口的简洁,维护这么小的模块不会那么复杂。
re: 我开始感到厌倦了... Kevin Lynx 2008-05-20 11:32
有同感,工作前很喜欢编程,身体越来越差,现在坐着就痛,编程的激情也被磨灭了。并且我薪水也低。所以很不爽。
re: 脚本编程琐话 Kevin Lynx 2008-05-16 17:46
= = 都忘了你以前是怎样的,貌似现在还可以
re: ACE与ASIO之间关于Socket编程的比较 Kevin Lynx 2008-05-15 19:56
@xbzg
忽略即可,基本上你还需要忽略其他几个默认链接的boost库
re: 彩虹岛游戏登陆过程分析 Kevin Lynx 2008-05-14 14:43
看能不能分析下网络封包?
re: 周记:找回激情 Kevin Lynx 2008-05-11 08:24
还是给个评论:
其实关于程序结构,其实就是我眼中的软件架构,这种东西的经验主要还是通过自己写大程序总结获得,配合设计模式软件工程之类的理论,上升得会比较快,尤其是写个库出来,更会挑战自己这方面的能力。简单的功能封装并不是一个库该干的(这话熟悉吧?)当然看其他开源库也会获取相关经验。对于boost我不敢说啥,很大很惶恐,只能单个小库地仰慕一下。
自我感觉现在有模板编程的思想,不过这东西,仅能用于基础模块的搭建。(我很满意我的日志类,用Andrei书中的术语就是policy :D和我的multi_list :D---Bugs眼中的过度设计--确实有点过度)
算法相关问题,我至今觉得那些书上的算法很少能带给我们直接的实践机会。可能你至今没在工作中用到DP吧?不过我从不忽视算法的作用,在我眼中算法是让人拥有坚实编程基础的东西。所以有时候解决一个问题的时候,总有点捉襟见肘的感觉。不过想想,没办法啊,环境所致。哥们你就忍了吧。
re: tcp要点学习-基础概念 Kevin Lynx 2008-05-09 18:08
@Xw.Y
我的意思是硬件那一层(网络协议栈)中的东西(链路层)
re: lua和python谁更适用于嵌入MMORPG? Kevin Lynx 2008-05-08 09:22
@test
感谢的经验分享,现在选择基本明了了,选lua也符合我自己的美学观念。:D
re: lua和python谁更适用于嵌入MMORPG? Kevin Lynx 2008-05-07 16:06
@Qestion
Stackless Python is an enhanced version of the Python programming language. It allows programmers to reap the benefits of thread-based programming without the performance and complexity problems associated with conventional threads. The microthreads that Stackless adds to Python are a cheap and lightweight convenience which can if used properly, give the following benefits:
Improved program structure.
More readable code.
Increased programmer productivity.
似乎很有意思
re: lua和python谁更适用于嵌入MMORPG? Kevin Lynx 2008-05-06 19:15
@剑孤寒
貌似有个tolua++可以很轻松地解决这个问题。
re: 让我痛苦得涕泪横流的Qt Kevin Lynx 2008-05-05 18:00
据说qt4与qt3(以及之前的版本)有很大变化。
我以前用QT基本上是在qt designer里做好了界面,然后再写代码,基本不用VS集成的那个。qmake其实挺好。
re: 调试经验总结-VC下的错误对话框 Kevin Lynx 2008-04-28 09:15
@yafare
例如?举个例子代码看看?(从对话框给的内容来看,似乎就是因为函数调用错误)
re: 累到想吐 Kevin Lynx 2008-04-24 20:32
我也累。。~_~##
还在加班。。。
@亨德列克
不是那一行错了,App和Game两个类分属不同模块,为了不让两个模块耦合,这里使用Listener *listener = (Listener*) p,而不是(App*)p。
giscn和eXile (他删除了他的第二条评论:) )的方法是正确的。可以被采用,再次表示感谢。
这让我意识到,void*在C++里缺乏安全性。