之前写的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. [转]优化数据库大幅度提高Oracle的性能

    几个简单的步骤大幅提高Oracle性能--我优化数据库的三板斧. 数据库优化的讨论可以说是一个永恒的主题.资深的Oracle优化人员通常会要求提出性能问题的人对数据库做一个statspack,贴出数据 ...

  2. 最近用unity5弄的一些渲染

    unity5 人皮渲染  Skin Shading 换了一种方法,优化了一下代码,unity5效果很好,消耗不大 点开可查看大图 加入了次表面散射的阴影与自阴影 unity5  ocean real- ...

  3. 如何禁止掉SharePoint页面个性化(网站操作-编辑页面)

    使用SharePoint Designer打开,或者创建一个新的Master Page,找到SPWebPartManager控件,如下所示,修改它的属性“Personalization-Enabled ...

  4. Spring笔记之(一)初探

    对spring框架的学习我是从模拟它的简单实现开始,这样也易于领悟到它的整个框架结构,以下是简单实现的代码: 配置文件:spring.xml <?xml version="1.0&qu ...

  5. 【Java基础】用LinkedList实现一个简单栈的功能

    栈的基本功能 栈的最基本功能是保障后进先出,然后在此基础上可以对在栈中的对象进行弹入弹出,此外,在弹出时,如果栈为空,则会报错,所以还需要提供获取当前栈大小的方法. 构造存储对象Student /** ...

  6. gcc编译选项的循环重复查找依赖库等命令

    link时,若liba.a依赖libb.a,若这样写 -lb -la,则链接通不过,gcc有个选项:-Xlinker ,可以让gcc在链接时反复查找依赖库,用法 : gcc -shared -o li ...

  7. 【原】用PHP搭建基于swoole扩展的socket服务(附PHP扩展的安装步骤及Linux/shell在线手册)

    最近公司的一项目中,需要用PHP搭建一个socket服务. 本来PHP是不适合做服务的,因为和第三方合作,需要采用高效而稳定的TCP协议进行数据通信.经过多次尝试,最终选择了开源的PHP扩展:swoo ...

  8. NSDictionary或NSArray与JSON字符串相互转换

    在iOS 5 中,苹果引入了一个解析JSON串的NSJSONSerialization类.通过该类,我们可以完成JSON数据与NSDictionary和NSArray之间的转化. 以前,我记得我用的是 ...

  9. [置顶] 单机版hadoop实例安装

    目标:运行单机版hadoop http://localhost:50030mapredule监控界面 http://localhost:50070HDFS监控页面 -->安装linux系统 -- ...

  10. linux命令之more

    转自:http://www.cnblogs.com/peida/archive/2012/11/02/2750588.html more命令,功能类似 cat ,cat命令是整个文件的内容从上到下显示 ...