boost python 多线程 纠结的一些问题

37 篇文章 0 订阅

用任何库之前一定要看看多线程。。。

 最近一直比较忙,不说那些整死人的专业课吧,写代码也比较忙,所以几乎没来更新。之前的引擎已经完全停止了,现在正在做的一个和网页有关的程序。里面涉及到的东西比较杂比较广。特别是多线程,能把人折磨透了。

    这个程序中间遇到的最郁闷的的3件事情写一下,我猜可能也会有人和我遇到同样的问题可以借鉴借鉴。

    1.UTF-8,UNICODE,GBK

    我不知道为什么我用wxWidgets的wxURL来下载有的网页的时候,无法得知文件的格式。通常大部分都是可以的,可以得到一个比如"text/html charset:utf-8"之类的,但是不是所有的都可以。
    首先让我迷惑的一点是UTF-8是什么,最后根据我的理解,(可能有错),UTF-8是相当于Luinix下面的Unicode的编码。之前写代码的时候都会自己把UNICHAR定义成一个typedef unsigned short,因为它在内存中占用的大小不会因为操作系统而改变。你在别的操作系统(或者是别的编译器?忘记了)下编译的话,可能会有的是4字节,有的是2字节,造成不一致。这里也暗示了可能操作系统对字符的处理会不大一样。这大概就是Luinix下面没有Unicode而有UFT-8的原因?具体UTF-8的编码是怎么编码的可以去查一下资料。它还有一个好处就是对于只含有ASCII码的内容,它的UTF-8编码就是ASCII码。这样的话对一些只能处理ASCII码的东西处理UTF-8至少不会出太致命的问题。而UNICODE下的比如a,b,c,1,2,3这些字符和ASCII码是不同的(在UltraEditor里面看应该就是在前面加了个00),
    有人在网上面说UTF-8的编码开头会有一个0xef,0xbb,0xbf三个char,那些其实是因为,在windows操作系统下,Unicode编码格式的文件是以oxff,oxfe开头的。这个Unichar按照UTF-8来编码就变成了上面说的那3个char了。所以一般来说,如果是在非windows操作系统下,UTF-8编码的文件是没有这个开头的,这就让人很郁闷了,那我怎么知道我拿到的这个文件是什么编码的呢?因为它还可以是比如gbk啊。
    gbk是什么呢?gbk相当于一个。。。嗯。。mutibyte?就是多字节字符集。比如a,b,c,1,2,3这些ASCII码则就是按照ASCII码编码的,而“一”“二”这些是按照Unicode编码的(而UTF-8则不是,则是用“一”“二”这些的Unicode编码经过一些计算来转换出来的编码)。所以现在就可以知道:
    0xff,0xfe开头的,Unicode
    0xef,0xbb,0xbf开头的,Unicode转化成的UTF-8
    其余的,UTF-8或者GBK。(比较稀有的就不说了)。
    所以啊,如果没有文件的charset,还是不知道怎么分辨UTF-8,GBK,(有谁知道怎么分辨?我很想知道,请告诉我一下,谢谢^^)
    另一个问题就是,wxWidgets提供的编码转换的类,那个UTF-8编码的,默认的是遇到非法的UTF-8就停止转换了。这就造成了问题。建议改成遇到非法的就换成某个替代的字符。
    在mysql中也有问题,之前不知道连接数据库要设置charset,由于数据库是gbk的,就把连接的charset设置为gbk的了。如果不设置的话,得到的内容就都是??,注意,不是乱码,就是问号。(如果是编码错误出来乱码你还可以自己转一下,但它就是给你问号)。
    这也需要注意一下。
    此外python脚本似乎只识别gbk的。如果你要写一个含有汉字的py文件,最好是用UltraEditor来写,因为记事本会自动存成Unicode,而python不识别0xff,0xfe,而且别忘了第一行要写上# coding=gbk
   

    2.该死的boost.python

    我几乎没找到资料来告诉我这些事情。。。
    首先就是boost上面的那些例子,里面凡是用到了boost::string的地方,请你一定要换成boost::python::str,我不知道我这里为什么不对,总之就是不对。
    第二个就是,你可能希望在你的c++里面调用python脚本,而你的python脚本里面调用你从c++导出的类,怎么做?你需要在Py_Initialize();后调用initxxxxx();
    这个initxxxxx();函数在
BOOST_PYTHON_MODULE(xxxxx)
{
 xxx xxx
}
里面被定义了。比如你的是
BOOST_PYTHON_MODULE(my_module)
{
 xxx xxx
}
那么你需要在Py_Initialize();后面调用initmy_module();
然后你就可以在你的py文件里面用这些你导出的c++类了。
    而且,这个宏如果你放到头文件里的话,会编译不成功。(不知道为什么,或许你不用预编译头的话就能编译成?)那么如果你要在别的.cpp或者别的文件里面调用initmy_module();就不行了,所以你需要先在某个.h里面声明一下:
    extern "C" __declspec(dllexport) void initmy_module();
    还有一个就是python脚本遇到异常了,你想看的话怎么办,我在网上看到一个办法,自己写一个类,比如:
class errCatcher:
    def __init__(self, filename):
        self.info = ''
        self.name = filename
        tmp = open(filename, 'w')
        tmp.close()
       
    def write(self, stuff):
        self.info += stuff

    def showmsg(self):
        do sth...



class outCatcher:
    def write(self, stuff):
        do sth...

sys.stderr = errCatcher('python_err.log')
sys.stdout = outCatcher()

    这个outCatcher会把那些print的操作变成执行write。
    而这个errCatcher会把异常保存起来,你还需要手动执行一下:

                try
                {
                      do some python script...
                 }
                catch(boost::python::error_already_set)
                {
                    PyErr_Print();
                    PyRun_SimpleString("sys.stderr.showmsg()");
                }
   来执行一下showmsg。
   关于python似乎比较郁闷的问题就这些了。

   3.多线程

   我发现第一次写多线程程序的时候可能都会这样。。。完全意识不到在使用别人的库的时候一定要去关心一下多线程。比如:
   3.1在子线程中使用wxURL,wxFTP之类的从wxSocketBase继承的类,一定要记得在最开始的时候手动调用一个wxSocketBase::Initialize();
   3.2在子线程中使用mysql记得mysql_thread_init();和mysql_thread_end();
   3.3在子线程中使用CrashRpt记得crInstallToCurrentThread()和crUninstallFromCurrentThread()
   3.4
   上面就是3.1比较隐含一点,因为它表现出来的是有的时候用GetInputStream的时候会得到NULL你还以为是网络卡没打开。而wxSocketBase::Initialize();的要求写在一个小小的角落里很容易被人忽视。
   更加隐含的一个错误就是在子线程中调用python脚本。这个太痛苦了。因为几乎它从来都不出错,几乎从来都没问题,但是偶尔就会出一些非常奇怪的问题,不,不会挂掉,只会是结果与你想象的不符合。
   在子线程中使用python的办法是这样的:首先你需要PyEval_InitThreads();
   因为我的python脚本本质上同时只运行一个,所以我这里实际是“单线程”,更复杂的情况就不知道了。
   我顺手就PyEval_ReleaseLock();以后谁要执行脚本谁来PyEval_AcquireLock();
   主线程中执行,就在执行前PyEval_AcquireLock();执行后PyEval_ReleaseLock();
   子线程中就这样,执行前:
            // get the global lock
            PyEval_AcquireLock();

            PyThreadState * mainThreadState = NULL;
            // save a pointer to the main PyThreadState object
            mainThreadState = PyThreadState_Get();

            // get a reference to the PyInterpreterState
            PyInterpreterState * mainInterpreterState = mainThreadState->interp;
            // create a thread state object for this thread
            m_pMyState = PyThreadState_New(mainInterpreterState);
            m_pSavedState = PyThreadState_Swap(m_pMyState);

执行后:
            PyThreadState_Swap(m_pSavedState);
            PyThreadState_Clear(m_pMyState);
            // delete my thread state object
            PyThreadState_Delete(m_pMyState);

            // release our hold on the global interpreter
            PyEval_ReleaseLock();
    还有很多更好的做法,你可以去网上查查看。

    大约极度头痛的事情就这些了。希望能给读文章的人一点点小小的借鉴。^^


From: http://blog.sina.com.cn/s/blog_4a5c75d40100ja26.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值