之前写的LIBPNG库学习小结介绍了怎么样自定义LIBPNG库的write、read、flush函数,而不使用LIBPNG库提供的默认函数。

上一篇讲述的都是在单线程的情况下,今天将程序升级,放在多线程下面跑,发现了几个问题:
首先说明一下:上一篇中是用struct保存的数据结构,而这次需要将数据封装在类中,因此程序有点小变动。以下是类的部分定义:

private:
png_infop m_pInfo;
png_structp m_pPng;
char *m_pImage;

其中m_pImage就是上一篇tData中的data。

上一篇中tData是全局定义的,在多线程的情况下会发生争抢资源的情况,可查看上一篇中的代码,在void PNGAPI png_own_write_data(png_structp png_ptr, png_bytep data, png_size_t length)函数中需要一个变量来存储每次写入的位置,不能每次都从第0个位置开始写吧?会争抢的资源就是这个记录位置的变量。这该怎么解决呢?

1-首先想到的办法就是将所有数据成员和函数成员作为类的私有成员访问即可解决问题,可是编译的时候却提示png_own_write_data()和png_own_flush()函数出错,具体错误信息就不写了,此路不通。

2.-加锁可以解决这个问题,但是加锁效率很低,怎么办呢?有没更好的办法?

想到的解决办法:

1-在png_struct中找一个闲置的字段来存储这个变量,可是我看完了png_struct的定义,也不确定那个变量是没有用的,虽然有很多字段的值从始至终都是0,但是我还是不敢贸然使用,因为不知道什么时候这个值就被使用了。

2-还是在png_struct中找一个闲置的字段,不过这次不是使用某个int或long型的变量了,而是使用函数指针,没错,就是   函数指针,因为任何指针在系统中都是一个内存地址(4字节),可以当做一个int类型来使用。

下面就详细的介绍一下这种方法:

1-首先锁定的是output_flush_fn,在上一篇中也说了,默认情况下

PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED

这个宏是没有被定义的,因此output_flush_fn()这个函数就一直不会执行,所以output_flush_fn这个函数指针是一直没有使用的,但是若使用自己编译的LIBPNG库,而恰好定义了上面的那个宏,那么这样程序就会发生意想不到的错误。因此此方法可以用,但是要慎重。

2-根据read和write的互斥性,我们可以交错的使用write_data_fn和read_data_fn这两个函数指针来保存这个偏移地址。因为我们一般不会在读的时候进行写,也不会在写的时候进行读操作(要是有这种情况,你还是老老实实的使用output_flush_fn吧,这种情况不适合你),所以我们在写的时候使用read_data_fn来保存写偏移地址,在读的时候使用write_data_fn来保存读偏移地址,具体请见代码:

void PNGAPI pngOwnReadData( png_structp pPng, png_bytep data, png_size_t length )
{
png_bytep src = (png_bytep)pPng->io_ptr;
//强制类型转换,获得偏移地址
int offSet = (int)pPng->write_data_fn;
memcpy( data, src + offSet, length );
offSet += length;
//将偏移地址强转成png_rw_ptr类型,该类型是png库定义的函数指针类型
pPng->write_data_fn = (png_rw_ptr)offSet;
}

而在读取的主函数里面必须有这样的代码:

void readPNG(…… )
{
png_voidp io_ptr = (void *)image;
//将write_data_fn初始化为0
m_pPng->write_data_fn = (png_rw_ptr);
png_set_read_fn( m_pPng, io_ptr, pngOwnReadData );
png_read_png( m_pPng, m_pInfo, PNG_TRANSFORM_EXPAND, NULL );
}

同样的写函数也具有同样的结构:

void PNGAPI pngOwnWriteData(png_structp pPng, png_bytep data, png_size_t length)
{
……
png_bytep src = (png_bytep)pPng->io_ptr;
int offSet = ( int )pPng->read_data_fn;
memcpy( src + offSet, data, length );
offSet += length;
pPng->read_data_fn = (png_rw_ptr)offSet;
……
}
char* writePNG(…… )
{
……
png_voidp io_ptr = (void *)m_pImage;
m_pPng->read_data_fn = (png_rw_ptr);
png_set_IHDR( m_pPng, m_pInfo, width, height, , PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT );
png_set_rows( m_pPng, m_pInfo, rgb );
png_set_write_fn( m_pPng, io_ptr, pngOwnWriteData, NULL );
png_write_png( m_pPng, m_pInfo, PNG_TRANSFORM_EXPAND, NULL );
//在对象销毁前获取长度信息
length = (int)m_pPng->read_data_fn;
png_destroy_write_struct( &m_pPng, &m_pInfo );
……
}

好,到此为止我们就实现了即保证了多线程的安全性,又保证了程序的效率,搞定,收工……

LIBPNG使用小结(二)的更多相关文章

  1. gulp使用小结(二)

    接上篇文章接Gulp使用小结(一) 内容如下: 首先,偶在gulp-demos上已经提交了个较通用的栗子...俺琢磨半天,原准备分阶段搞些 Gulp 套路,但是写完介个栗子之后,觉得已经能覆盖绝大多数 ...

  2. Vue学习小结(二)

    接上一批,小结(二). 三.导航内容(含左侧导航及顶部面包屑导航) 其实导航条主要根据element-ui的教程进行编写,官网:http://element-ui.cn/#/zh-CN/compone ...

  3. python --- 字符编码学习小结(二)

    距离上一篇的python --- 字符编码学习小结(一)已经过去2年了,2年的时间里,确实也遇到了各种各样的字符编码问题,也能解决,但是每次都是把所有的方法都试一遍,然后终于正常.这种方法显然是不科学 ...

  4. Element Vue 开箱即用框架如何使用-测试开发【提测平台】阶段小结(二)

    微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 上一篇总结了后端服务接口的开发,这篇我们主要来总结下前后端分离开发中的前端部分,主要是开箱即用的框架介绍和之前章节组件的梳理和部分的扩展内 ...

  5. Spring知识点小结(二)

    一.配置非自定义的Bean(数据源DataSource模型) DBCP数据源:        导入dbcp的jar包:dbcp+pool+connector                代码实现:  ...

  6. 动态规划小结 - 二维动态规划 - 时间复杂度 O(n*n)的棋盘型,题 [LeetCode] Minimum Path Sum,Unique Paths II,Edit Distance

    引言 二维动态规划中最常见的是棋盘型二维动态规划. 即 func(i, j) 往往只和 func(i-1, j-1), func(i-1, j) 以及 func(i, j-1) 有关 这种情况下,时间 ...

  7. Hibernate知识点小结(二)

    一.持久化对象和标识符    1.持久化类        配置完关系后,操作的实体对应的类,成为持久化类 (Customer) 2.持久化类标识符(oid:object id)        3.持久 ...

  8. Struts2知识点小结(二)

    一.结果视图的配置    <result name="success">/success.jsp</result>        1.局部结果视图      ...

  9. Java并发包中常用类小结(二)

    6.ThredPoolExecutor ThredPoolExecutor是基于命令模式下的一个典型的线程池的实现,主要通过一些策略实现一个典型的线程池,目前已知的策略有ThreadPoolExecu ...

随机推荐

  1. 为EF DbContext生成的实体添加注释(T5模板应用)[转]

    1 先加上类注释 找到这行代码WriteHeader(codeStringGenerator, fileManager): 在它下面加上我们的代码: string summary=string.Emp ...

  2. 【CSS3】Advanced7:CSS Transitions

    1.animate parts of your design without the need for the likes of JavaScrip 2.allowing smooth animati ...

  3. Call Hierarchy(方法调用层次)

    在VS2010中的一项新功能:Call Hierarchy窗口,它可以审查代码,确定方法在哪里调用,以及它们与其他方法的关系. 打开一个类文件,找有方法体实现代码的方法,右键选择View Call H ...

  4. mac使用初级

    imac使用的是login shell,所有开启一个terminal的时候,不会运行.bashrc文件,而是运行.bash_profile文件,因此只需要中home目录新建一个.bash_profil ...

  5. poj1515--Street Directions(边的双连通)

    给一个无向图,要求变成强连通的有向图,需要保留哪些边. 边的双连通,对于桥保留两条边,其他的只保留一条边.求双连通的过程中记录保留边. /******************************* ...

  6. 在YII中使用Redis等缓存

    Yii AR 单行数据-自动缓存机制 | LOCKPHP Yii AR 单行数据-自动LOG机制 CActiveRecordBehavior进阶 | LOCKPHP 缓存 - 权威指南 - Yii F ...

  7. Java开发中常见的危险信号(中)

    本文来源于我在InfoQ中文站原创的文章,原文地址是:http://www.infoq.com/cn/news/2013/12/common-red-flags-in-java-1 Dustin Ma ...

  8. js showModalDialog打开新的页面给原页面传值问题

    a.html中打开一个新页面b.html,b.html页面给a.html中的input传一个值并将value赋给input框. a.html: <html>  <head>   ...

  9. Java用OpenOffice将word转换为PDF

    一.      软件安装以及jar包下载 官网的下载地址如下(英文): OpenOffice 下载地址http://www.openoffice.org/ JodConverter 下载地址http: ...

  10. background-position也许你没考虑到

    设置背景图片时不知你有没有遇到过背景位置的困扰,有没有深入思考过,background-position到底是什么,下面请各位看看我的理解. 简而言之就一句话,默认图片左上角居元素左上角的坐标,例如: ...