存档在 2013年3月

Linux Epoll ET模式EPOLLOUT和EPOLLIN触发时刻

2013年3月25日

ET模式称为边缘触发模式,顾名思义,不到边缘情况,是不会触发的。

EPOLLOUT事件:
EPOLLOUT事件只有在连接时触发一次,表示可写,其他时候想要触发,那你要先准备好下面条件:
1.某次write,写满了发送缓冲区,返回错误码为EAGAIN。
2.对端读取了一些数据,又重新可写了,此时会触发EPOLLOUT。
简单地说:EPOLLOUT事件只有在不可写到可写的转变时刻,才会触发一次,所以叫边缘触发,这叫法没错的!

其实,如果你真的想强制触发一次,也是有办法的,直接调用epoll_ctl重新设置一下event就可以了,event跟原来的设置一模一样都行(但必须包含EPOLLOUT),关键是重新设置,就会马上触发一次EPOLLOUT事件。

EPOLLIN事件:
EPOLLIN事件则只有当对端有数据写入时才会触发,所以触发一次后需要不断读取所有数据直到读完EAGAIN为止。否则剩下的数据只有在下次对端有写入时才能一起取出来了。
现在明白为什么说epoll必须要求异步socket了吧?如果同步socket,而且要求读完所有数据,那么最终就会在堵死在阻塞里。

腾讯公司后台服务器经典面试题 (2009年5月)

2013年3月25日

1, 使用Linux epoll模型,水平触发模式(Level-Triggered);当socket可写时,会不停的触发socket可写的事件,如何处理?
2, 从socket读数据时,socket缓存里的数据,可能超过用户缓存的长度,如何处理? 例如,socket缓存有8kB的数据,而你的缓存只有2kB空间。
3, 向socket发送数据时, 可能只发送了用户缓存里的一半,如何处理?例如,需要向socket发送8kB数据,返回值只有2kB发送成功。
4, C++的虚函数是怎么实现的?
5, C++的虚函数有什么作用? » 阅读更多: 腾讯公司后台服务器经典面试题 (2009年5月)

Linux下C/C++使用GKeyFile读取配置文件

2013年3月25日

对于GKeyFile生成的格式文件,同样可以通过此数据结构进行读取文件中的配置信息,生成的配置文件内容为:

[STARTUP]
x=300
y=600
center=true
timestamp=1314432584
random=0.78204092288815774

[PATH]
bin_path=/bin;/sbin;/usr/bin;/usr/local/bin;/home/jcodeer/bin;

这次使用GKeyFile将其中的每一键项读取出来,进行输出。程序代码:

#include <glib.h>

int main(int argc,char** argv){
    GKeyFile* config = g_key_file_new();
    g_key_file_load_from_file(config,"./019.ini",G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS,NULL);
    
    #define STARTUP "STARTUP"
    #define PATH    "PATH"

    gchar* x = g_key_file_get_value(config,STARTUP,"x",NULL);
    g_print("x = %s\n",x);

    gchar* y = g_key_file_get_string(config,STARTUP,"y",NULL);
    g_print("y = %s\n",y);

    gboolean center = g_key_file_get_boolean(config,STARTUP,"center",NULL);
    g_print("center = %d\n",center);

    gint timestamp = g_key_file_get_integer(config,STARTUP,"timestamp",NULL);
    g_print("timestamp = %u\n",timestamp);

    gdouble random = g_key_file_get_double(config,STARTUP,"random",NULL);
    g_print("random = %0.10f\n",random);

    gsize length,i;
    gchar** bin_path = g_key_file_get_string_list(config,PATH,"bin_path",&length,NULL);
 
    g_print("bin_path=");
    for(i = 0; i < length;i++){
        g_print("%s;",bin_path[i]);
    }
    g_print("\n");

    #undef STARTUP
    #undef PATH

    g_key_file_free(config);
    return 0;
}

Linux下C/C++使用GKeyFile生成配置文件

2013年3月25日

还记得Windows使用的配置文件吗?看看boot.ini文件内容

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(2)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(2)\WINDOWS=”Windows Server 2003, Standard” /fastdetect /NoExecute=OptOut
C:\wubildr.mbr = “Ubuntu” » 阅读更多: Linux下C/C++使用GKeyFile生成配置文件

C++实现中介者设计模式在项目中应用

2013年3月24日

项目中存在机器人类,路径规划类,串口类,分别为:Robot ,RobotPathPlan,RobotSerial
robot.h

#ifndef ROBOT_H_
#define ROBOT_H_
class Mediator;
class Robot
{
public:
	Robot(Mediator *);
	void sendMsg(int n);
	void setPoint(int p);
	int getSonarByIndex(int i);
	void processData();
private:
	Mediator *mediator;
};
#endif

robot.cpp

#include "robot.h"
#include "mediator.h"
#include <iostream>
using namespace std;

Robot::Robot(Mediator* media) : mediator(media){}
void Robot::sendMsg(int n)
{
	mediator->sendMsg(n);
}
void Robot::setPoint(int p)
{
	mediator->setPoint(p);
}
int Robot::getSonarByIndex(int i)
{
	cout<<"获取第"<<i<<"个超声波"<<endl;
	return 1;
}
void Robot::processData()
{
	cout<<"机器人类开始处理数据"<<endl;
}

pathplan.h

#ifndef PATHPLAN_H_
#define PATHPLAN_H_
class Mediator;
class PathPlan
{
public:
	PathPlan(Mediator* media);
	int getSonarByIndex(int i);
	void setPoint(int p);
private:
	Mediator *mediator;
};

#endif

pathplan.cpp

#include "pathplan.h"
#include "mediator.h"
#include <iostream>
using namespace std;

PathPlan::PathPlan(Mediator* media) : mediator(media){}
int PathPlan::getSonarByIndex(int i) 
{
	return mediator->getSonarByIndex(i);
}

void PathPlan::setPoint(int p)
{
	cout<<"设置机器人目标点为"<<p<<endl;
}

robotserial.h

#ifndef ROBOTSERIAL_H_
#define ROBOTSERIAL_H_
class Mediator;

class RobotSerial
{
public:
	RobotSerial(Mediator* media);
	void sendMsg(int n);
	void processData();

private:
	Mediator *mediator;
};
#endif 

robotserial.cpp

#include "robotserial.h"
#include "mediator.h"
#include <iostream>
using namespace std;

RobotSerial::RobotSerial(Mediator* media) : mediator(media){}

void RobotSerial::sendMsg(int n)
{
	cout<<"发送命令"<<n<<endl;
}
void RobotSerial::processData()
{
	mediator->processData();
}

mediator.h

#ifndef MEDIATOR_H_
#define MEDIATOR_H_
class Robot;
class RobotSerial;
class PathPlan;

class Mediator
{
public:
	void registRobot(Robot *tRobot);
	void registRobotSerial(RobotSerial* tRobotSerial);
	void registPathPlan(PathPlan *tPathplan);

	void setPoint(int p);
	int getSonarByIndex(int i);
	void sendMsg(int n);
	void processData();
private:
	Robot *robot;
	RobotSerial *robotSerial;
	PathPlan *pathPlan;
};
#endif 

mediator.cpp

#include "mediator.h"
#include "robot.h"
#include "robotserial.h"
#include "pathplan.h"

void Mediator::registRobot(Robot *tRobot){robot = tRobot;}
void Mediator::registRobotSerial(RobotSerial* tRobotSerial){robotSerial = tRobotSerial;}
void Mediator::registPathPlan(PathPlan *tPathPlan) { pathPlan = tPathPlan;}

void Mediator::setPoint(int p)
{
	pathPlan->setPoint(p);
}
int Mediator::getSonarByIndex(int i)
{
	return robot->getSonarByIndex(i);
}
void Mediator::sendMsg(int n)
{
	robotSerial->sendMsg(n);
}
void Mediator::processData()
{
	robot->processData();
}

main.cpp

#include "robot.h"
#include "robotserial.h"
#include "pathplan.h"
#include "mediator.h"

int main()
{
	Mediator media;
	Robot robot(&media);
	RobotSerial robotSerial(&media);
	PathPlan pathPlan(&media);
	media.registRobot(&robot);
	media.registRobotSerial(&robotSerial);
	media.registPathPlan(&pathPlan);
	pathPlan.getSonarByIndex(1);
	robot.setPoint(1);

	robot.sendMsg(2);
	robotSerial.processData();
}

为什么C++编译器不能支持对模板的分离式编译

2013年3月23日

为什么C++编译器不能支持对模板的分离式编译

刘未鹏(pongba)

首先,一个编译单元(translation unit)是指一个.cpp文件以及它所#include的所有.h文件,.h文件里的代码将会被扩展到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件(假定我们的平台是win32),后者拥有PE(Portable Executable,即windows可执行文件)文件格式,并且本身包含的就已经是二进制码,但是不一定能够执行,因为并不保证其中一定有main函数。当编译器将一个工程里的所有.cpp文件以分离的方式编译完毕后,再由连接器(linker)进行连接成为一个.exe文件。 » 阅读更多: 为什么C++编译器不能支持对模板的分离式编译

类模板的成员函数为什么不能分离式编译

2013年3月23日

以下的代码是为了定义一个具有回调功能的类,并进行测试。为了针对任意类型都可使用,我们使用模板来泛化这个类,定义如下:
serial.h

#ifndef SERIAL_H_
#define SERIAL_H_
template
class Serial
{
	typedef  void(T::*Func)(void);
public:
	Serial();
	~Serial();
	void setTObject(T* t);
	void setCallBackFunc(Func tFunc);
	void callFunc();
private:
	T* tObject;
	Func func;
};
#endif

serial.cpp

#include "serial.h"
#include
using namespace std;

template Serial::Serial(){}
template Serial::~Serial(){}

template
void Serial::setTObject(T* t)
{
		tObject = t;
}
template
void Serial::setCallBackFunc(Func tFunc)
{
	func = tFunc;
}

template
void Serial::callFunc()
{
	(tObject->*func)();
}

robot.h

#ifndef ROBOT_H_
#define ROBOT_H_
#include
using namespace std;
class Robot
{
public:
	void myFunc(void){cout<<"测试"<<endl;}
};
#endif

main.cpp

#include "robot.h"
#include "serial.h"
#include
using namespace std;

int main()
{
	Serial mySerial;
	Robot *robot = new Robot();
	mySerial.setTObject(robot);
	mySerial.setCallBackFunc(&Robot::myFunc);
	mySerial.callFunc();
	delete robot;
}

出现编译错误如下

/tmp/ccuMoBaX.o: In function `main':
main.cpp:(.text+0x13): undefined reference to `Serial::Serial()'
main.cpp:(.text+0x37): undefined reference to `Serial::setTObject(Robot*)'
main.cpp:(.text+0x55): undefined reference to `Serial::setCallBackFunc(void (Robot::*)())'
main.cpp:(.text+0x61): undefined reference to `Serial::callFunc()'
main.cpp:(.text+0x79): undefined reference to `Serial::~Serial()'
main.cpp:(.text+0x95): undefined reference to `Serial::~Serial()'

» 阅读更多: 类模板的成员函数为什么不能分离式编译

用visio画UML类图

2013年3月20日

对于画类图的工具很多,曾经学过用starUML画类图,但这个是用于Java语言的,对于用vs编程C++语言,个人感觉用visio会好一点。以下用以前面的俄罗斯方块游戏中的一个Block类为例来讲述 » 阅读更多: 用visio画UML类图