任何减少boost :: spirit编译时间的想法?
我刚刚将flex解析器移植到boost :: spirit.EBNF有大约25条规则.
结果运行良好,运行时性能良好.
问题是编译需要永远!它需要大约十分钟,并且需要几乎一千兆字节的内存.原始的flex解析器在几秒钟内编译完成.
我正在使用boost版本1.44.0和Visual Studio 2008.
在Joel de Guzman的文章"最佳实践"中,它说
具有复杂定义的规则严重损害了编译器.我们已经看到超过一百行的规则,需要花费几分钟来编译
好吧,我没有接近那么久,但我的编译仍然需要超过几分钟
这是我语法中最复杂的部分.它是以某种方式分解成较小部分的候选者吗?
rule
= ( tok.if_ >> condition >> tok.then_ >> *sequel ) [ bind( &cRuleKit::AddRule, &myRulekit ) ]
| ( tok.if_ >> condition >> tok.and_ >> condition >> tok.then_ >> *sequel ) [ bind( &cRuleKit::AddRule, &myRulekit ) ]
;
condition
= ( tok.identifier >> tok.oper_ >> tok.value ) [ bind( &cRuleKit::AddCondition, &myRulekit, _pass, _1, _2, _3 ) ]
| ( tok.identifier >> …Run Code Online (Sandbox Code Playgroud) (这是我原始问题的简化版)
我有几个线程写入boost asio socket.这看起来效果很好,没有任何问题.
文档说共享套接字不是线程安全的(这里,在底部向下)所以我想知道我是否应该使用互斥锁等保护套接字.
这个问题坚持认为保护是必要的,但没有就如何保护提出建议.
我原来问题的所有答案也坚持我做的很危险,并且大多数人都敦促我用async_writes或更复杂的东西替换我的写作.但是,我不愿意这样做,因为它会使已经正常工作的代码变得复杂,并且没有一个回答者说服他们知道他们所说的内容 - 他们似乎已经阅读了与我相同的文档并且正在猜测,就像我一样是.
所以,我编写了一个简单的程序来强调测试从两个线程写入共享套接字.
这是服务器,它只是写出从客户端收到的任何内容
int main()
{
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 3001));
tcp::socket socket(io_service);
acceptor.accept(socket);
for (;;)
{
char mybuffer[1256];
int len = socket.read_some(boost::asio::buffer(mybuffer,1256));
mybuffer[len] = '\0';
std::cout << mybuffer;
std::cout.flush();
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是客户端,它创建两个线程,尽可能快地写入共享套接字
boost::asio::ip::tcp::socket * psocket;
void speaker1()
{
string msg("speaker1: hello, server, how are you running?\n");
for( int k = 0; k < 1000; k++ ) {
boost::asio::write(
*psocket,boost::asio::buffer(msg,msg.length()));
}
}
void speaker2()
{ …Run Code Online (Sandbox Code Playgroud) 我已经在64位Windows 7机器上安装了com0com v2.2.2.0,显然是成功的.
我运行命令实用程序,如下所示:
command> install PortName=COM9 PortName=COM8
CNCA0 PortName=COM9
CNCB0 PortName=COM8
ComDB: COM8 - logged as "in use"
ComDB: COM9 - logged as "in use"
command> busynames COM?*
COM3
COM4
COM5
COM6
COM8
COM9
COMPOSITEBATTERY
Run Code Online (Sandbox Code Playgroud)
注意:记录为"正在使用"不是错误消息?
然后我尝试像这样打开COM8
m_hIDComDev = CreateFileA( szCodedPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );
if( m_hIDComDev == NULL || m_hIDComDev == INVALID_HANDLE_VALUE ) {
wchar_t * lpMsgBuf;
DWORD dw = ::GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw, …Run Code Online (Sandbox Code Playgroud) 我有一个接收,处理和传输UDP数据包的应用程序.
如果接收和传输的端口号不同,一切正常.
如果端口号相同且IP地址不同,则当IP地址与运行应用程序的计算机位于同一子网时,通常可以正常工作.在最后一种情况下,send_to函数需要几秒钟才能完成,而不是通常的几毫秒.
Rx Port Tx IP Tx Port Result
5001 Same 5002 OK Delay ~ 0.001 secs
subnet
5001 Different 5001 OK Delay ~ 0.001 secs
subnet
5001 Same 5001 Fails Delay > 2 secs
subnet
Run Code Online (Sandbox Code Playgroud)
这是一个演示问题的简短程序.
#include <ctime>
#include <iostream>
#include <string>
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::udp;
using std::cout;
using std::endl;
int test( const std::string& output_IP)
{
try
{
unsigned short prev_seq_no;
boost::asio::io_service io_service;
// build the input socket
/* This is connected to a UDP client …Run Code Online (Sandbox Code Playgroud) 使类线程安全的直接方法是添加互斥锁属性并在访问器方法中锁定互斥锁
class cMyClass {
boost::mutex myMutex;
cSomeClass A;
public:
cSomeClass getA() {
boost::mutex::scoped_lock lock( myMutex );
return A;
}
};
Run Code Online (Sandbox Code Playgroud)
问题是这使得该类不可复制.
我可以通过使互斥锁成为静态来使事情发挥作用.但是,这意味着当访问任何其他实例时,类的每个实例都会阻塞,因为它们都共享相同的互斥锁.
我想知道是否有更好的方法?
我的结论是没有更好的方法.使用私有静态互斥锁属性创建一个线程安全的类是"最好的": - 它很简单,它有效,它隐藏了尴尬的细节.
class cMyClass {
static boost::mutex myMutex;
cSomeClass A;
public:
cSomeClass getA() {
boost::mutex::scoped_lock lock( myMutex );
return A;
}
};
Run Code Online (Sandbox Code Playgroud)
缺点是类的所有实例共享相同的互斥锁,因此不必要地相互阻塞.这不能通过使互斥属性非静态(因此为每个实例赋予其自己的互斥锁)来解决,因为如果正确完成,复制和赋值的复杂性是噩梦般的.
如果需要,各个互斥锁必须由外部不可复制的单例管理,并在创建时为每个实例建立链接.
感谢所有的回复.
有几个人提到编写我自己的复制构造函数和赋值运算符.我试过这个.问题是我的真正的类具有许多在开发期间总是在变化的属性.维护复制构造函数和assignmet运算符是繁琐且容易出错的,错误导致难以发现错误.让编译器为复杂类生成这些是一个巨大的节省时间和bug减少器.
许多响应都关注使复制构造函数和赋值运算符是线程安全的.这个要求为整个事情增加了更多的复杂性!幸运的是,我不需要它,因为所有复制都是在单个线程中进行设置时完成的.
class cSafe {
boost::mutex myMutex;
cSomeClass A;
public:
cSomeClass getA() {
boost::mutex::scoped_lock lock( myMutex );
return A;
}
(copy constructor)
(assignment op )
};
class cMyClass …Run Code Online (Sandbox Code Playgroud) 我应该如何修改访问者内部顶点的捆绑属性?
我想使用简单的子脚本编写方法,但传递给访问者的图形参数是const,因此编译器不允许更改.
我可以在访问者中存储对图表的引用,但这看起来很奇怪.
/**
A visitor which identifies vertices as leafs or trees
*/
class bfs_vis_leaf_finder:public default_bfs_visitor {
public:
/**
Constructor
@param[in] total reference to int variable to store total number of leaves
@param[in] g reference to graph ( used to modify bundled properties )
*/
bfs_vis_leaf_finder( int& total, graph_t& g ) :
myTotal( total ), myGraph( g )
{
myTotal = 0;
}
/**
Called when the search finds a new vertex
If the vertex has no children, it …Run Code Online (Sandbox Code Playgroud) 该boost::spirit文档有重要的警示
有不同的方式来写语义动作为Spirit.Qi:使用普通函数
Boost.Bind,Boost.Lambda或Phoenix.后三种允许你使用特殊的占位符来控制参数配置(_1,_2,等).每个库都有自己的占位符实现,所有这些都在不同的命名空间中.您必须确保不将占位符与不属于的库混合,并且在编写语义操作时不使用不同的库.通常,for
Boost.Bind,use::_1,::_2等等(是的,这些占位符在全局命名空间中定义).对于
Boost.Lambda使用在命名空间中定义的占位符boost::lambda.对于使用Phoenix编写的语义操作,请使用命名空间中定义的占位符
boost::spirit.请注意,为方便起见,所有现有占位符也可从命名空间中获得boost::spirit::qi
(文件)
好的,所以我写了这段代码
template <typename Iterator>
struct ruleset_grammar : qi::grammar<Iterator>
{
template <typename TokenDef>
ruleset_grammar(TokenDef const& tok)
: ruleset_grammar::base_type(start)
{
start = *( tok.set_name [ boost::bind( &cRuleSet::setName, &theRuleSet, ::_1 ) ]
)
;
}
qi::rule<Iterator> start;
};
Run Code Online (Sandbox Code Playgroud)
请注意使用 ::_1
但是,我仍然得到此编译器错误
c:\documents and settings\james\spirit_test.cpp(138) : error C2872: '_1' : ambiguous …Run Code Online (Sandbox Code Playgroud) 我一直试图将我的计时器连接到一个函数.在我的派生类中,我在做什么
Timer->SetOwner(this,wxID_Timer);
Timer->Connect(wxID_Timer,wxTimerEventHandler( Window::OnUpdate ), NULL, this );
Run Code Online (Sandbox Code Playgroud)
我的OnUpdate声明在哪里
void OnUpdate( wxTimerEvent& event );
Run Code Online (Sandbox Code Playgroud)
任何人都可以告诉我这里有什么问题,为什么在我启动计时器后没有定期调用OnUpdate?谢谢,麻烦您了.
另外我没有使用静态事件表.关于wxTimer的其他答案对我没有帮助.
从多个并行线程读取STL容器是安全的.但是,表现很糟糕.为什么?
我创建了一个小对象,它在multiset中存储了一些数据.这使得构造函数相当昂贵(在我的机器上大约有5个usecs.)我在大型多集中存储了数十万个小对象.处理这些对象是一项独立的业务,因此我在多核机器上运行的线程之间拆分工作.每个线程从大型多集合中读取所需的对象,并对其进行处理.
问题是来自大型多重集的读取并不是并行进行的.看起来一个线程中的读取会阻塞另一个线程中的读取.
下面的代码是我能做到的最简单的代码,但仍然显示问题.首先,它创建一个包含100,000个小对象的大型多重集,每个小对象都包含自己的空多集.然后它将串联两次调用multiset复制构造函数,然后再并行调用两次.
分析工具显示串行拷贝构造函数大约需要0.23秒,而并行分析构建器需要两倍的时间.不知何故,并行副本互相干扰.
// a trivial class with a significant ctor and ability to populate an associative container
class cTest
{
multiset<int> mine;
int id;
public:
cTest( int i ) : id( i ) {}
bool operator<(const cTest& o) const { return id < o.id; }
};
// add 100,000 objects to multiset
void Populate( multiset<cTest>& m )
{
for( int k = 0; k < 100000; k++ )
{
m.insert(cTest(k));
}
}
// copy construct multiset, called …Run Code Online (Sandbox Code Playgroud) 这显然是一个相当简单的问题,因为没有其他人在图书馆遇到过这样的问题。
但是,当我运行我的程序时,boost 返回错误“无法识别的选项 Settings.Directoy”但是我已经在我的代码和我要求它读取的文件中定义了它。首先这是我的代码,很短,因为我是作为测试来做的。
std::string Directory;
try {
ifstream Config_File("Config.ini");
options_description Game("Settings");
Game.add_options()
("Directory", value<std::string>(&Directory)->default_value("Example.exe"));
variables_map vm;
store(parse_config_file(Config_File, Game), vm);
notify(vm);
if (vm.count("Directory"))
{
cout << Directory;
}
}
catch(std::exception& E)
{
std::cout << E.what() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
这是它从“Config.ini”中读取的文件
[Settings]
Directory = "Example.exe"
Run Code Online (Sandbox Code Playgroud)
我已经尝试通过更改文件类型、名称...删除空格来调试它?
为目录中的条目添加和删除引号?很多事情,这给了我没有解决方案。
c++ ×9
boost ×4
boost-asio ×2
boost-spirit ×2
boost-graph ×1
boost-thread ×1
com0com ×1
file ×1
sockets ×1
stl ×1
udp ×1
winapi ×1
windows ×1
wxwidgets ×1