如何获得有效的 x64 THREADSAFE Ghostscript DLL

Posted

技术标签:

【中文标题】如何获得有效的 x64 THREADSAFE Ghostscript DLL【英文标题】:How to get a working x64 THREADSAFE Ghostscript DLL 【发布时间】:2020-09-15 11:18:54 【问题描述】:

主要背景

我们实际上是在尝试获取 Ghostscript x64 DLL 的多线程版本,以便通过 Ghostscript .NET 使用它。这个组件应该“允许在单个进程中同时运行多个 Ghostscript 实例”,但是,正如我们在项目中检查的那样,在向应用程序发出并发请求之前工作正常。可以使用Tasks 以相同的方法复制相同的行为。在这两种情况下引发的错误描述是:

调用“gsapi_new_instance”时出错:-100

即使它似乎与 .NET 没有直接关系,我也会发布我们的 C# 方法代码示例,仅用于上下文化。

// Define switches...
string[] switchesArray = switches.ToArray();

using (GhostscriptProcessor procesador = new GhostscriptProcessor())

    try
    
        procesador.StartProcessing(switchesArray, null);

        byte[] destinationFile = System.IO.File.ReadAllBytes(destinationPath);

        return destinationFile;

    
    catch (Exception ex)
    
        throw ex;
    
    finally
    
        System.IO.File.Delete(sourceFile);
    

线程安全解决方案

开始我们的调查,我们在this post 上找到了这个 KenS 的答案,表明 Ghostscript DLL 必须使用 GS_THREADSAFE 编译器定义生成。

澄清一下,当我们使用 Ghostscript 9.52 x64 来生成 PDF 时,我们需要为发布配置编译这个 x64 DLL。在尝试在 Windows 10 x64 机器上编译 Ghostscript 源代码后,使用 Visual Studio Community 2017 和 Visual Studio Community 2019,我们终于设法在没有 GS_THREADSAFE 参数的情况下构建和生成所有项目(仅限 VS Community 2019),只是为了确认编译正常,我们检查 DLL 和可执行文件是否正常工作。对于这个过程,我们考虑了我们在Ghostscript official documentation 中找到的所有内容。

由于我们没有其他指南来包含此 GS_THREADSAFE 参数,我们按照this solution 中给出的说明进行操作,包括有关 nmake 构建命令的 XCFLAGS="-DGS_THREADSAFE=1",将这句话用于全部重建 选项:

cd .. && nmake -f psi\msvc32.mak WIN64= SBR=1 DEVSTUDIO= XCFLAGS=-DGS_THREADSAFE=1 && nmake -f psi\msvc32.mak WIN64= DEVSTUDIO= XCFLAGS=-DGS_THREADSAFE=1 bsc

这种方法,在构建过程中会报错:

Error LNK2019 unresolved external symbol errprintf_nomem referenced in 函数 gs_log_error 文件 \mkromfs.obj 1

看起来,文件 mkromfs.c 有一个名为 errprintf_nomem 的方法,它不能设置 GS_THREADSAFE 时可以找到。

问题

1 - 是否存在包含编译为 THREADSAFE 的 x64 DLL 的 Ghostscript 公开版本?

而且,如果不是(这就是我的猜测......)

2 - 是否可以在不更改源代码的情况下将此 DLL 设为 THREADSAFE?

3- 谁能提供分步指南或演练,以在 Windows 10 x64 上使用 GS_THREADSAFE 构建 x64 Ghostscript DLL?

4 - 一些帖子谈到人们使用 Ghostscript .NET 管理多线程。我假设这些示例都使用 GS_THREADSAFE DLL...我们是否通过了其他解决方法?

非常感谢。

【问题讨论】:

我投票结束这个问题,因为这不是一个编程问题,它对 Ghostscript 的技术支持。 看看这个例子:github.com/jhabjan/Ghostscript.NET/blob/master/… 这个方法告诉 Ghostscript.NET 将每个 ghostscript dll 实例加载到它自己的内存空间中,因此允许多个实例同时运行。 非常感谢你,约瑟普。我们之前一定忽略了这一步。包括 ConsoleStdIo 的自定义类,并将此类的新实例添加到处理器的代码行中,正如它在示例中所表示的那样,就像一个魅力。仍在等待在更具挑战性的环境中尝试此方法,但我们使用这种方法进行的第一次负载测试留下了有希望的结果。请将此作为回复,我很乐意将此标记为答案,因为这解决了我的所有问题。希望帖子没有关闭,答案有一个编程解决方案,这对我们来说非常重要。 【参考方案1】:

总结所有这些问题,并作为未来开发人员遇到同样问题的指南,以下是我们迄今为止找到的答案:

    @KenS 在他的回复中提到:“不,Ghostscript 开发人员实际上并没有构建二进制文件的线程安全版本。”

    目前,显然不是,正如 this opened bug 所报道的那样。

    由于这似乎是商业许可支持的问题,我们不再对这一点发表评论。

    再次感谢@HABJAN。我绝对收回我对我的问题所说的话,因为可以让 Ghostscript .NET 处理多线程场景。下面是我们应用的解决方案,以防它对某人有用。

基于 HABJAN 示例,我们所做的是创建一个自定义类来捕获 Ghostscript 日志记录:

protected class ConsoleStdIO : Ghostscript.NET.GhostscriptStdIO

    public ConsoleStdIO(bool handleStdIn, bool handleStdOut, bool handleStdErr) : base(handleStdIn, handleStdOut, handleStdErr)
    
    

    public override void StdIn(out string input, int count)
    
        char[] userInput = new char[count];
        Console.In.ReadBlock(userInput, 0, count);
        input = new string(userInput);
    

    public override void StdOut(string output)
    
        //log
    

    public override void StdError(string error)
    
        //log
    

对于我们之前的方法,我们简单地包含对此类的调用,这样可以避免同时执行多个任务时出错:

// Define switches...
string[] switchesArray = switches.ToArray();

using (GhostscriptProcessor procesador = new GhostscriptProcessor())

    try
    
        procesador.StartProcessing(switchesArray, new ConsoleStdIO(true, true, true));

        byte[] destinationFile = System.IO.File.ReadAllBytes(destinationPath);

        return destinationFile;

    
    catch (Exception ex)
    
        throw ex;
    
    finally
    
        System.IO.File.Delete(sourceFile);
    

【讨论】:

【参考方案2】:

嗯,在我看来,您是在这里寻求技术支持。

您显然想在商业活动中使用 Ghostscript,实际上有人可能会合理地说您想要一个企业版的 Ghostscript。大概您不想更改源代码以允许您使用开源许可证,因为您不想为商业许可证付费。

考虑到这一点,您的问题的答案是:

    不,Ghostscript 开发人员实际上并未构建二进制文件的线程安全版本。 目前,没有。这可能是一个疏忽。 这将是一个技术支持问题,不能保证免费用户的技术支持,这是双许可证供应商说服人们使用商业许可证的少数几个杠杆领域之一。所以我希望你能理解我不会提供那个。 据我所知,没有。

【讨论】:

感谢您的回答,肯。直到此刻,我们在我们的解决方案中尝试了 Ghostscript,我们向 Artifex 公开了我们的计划和背景,以确保我们实际上可以避免获得商业许可证(商业部门确认了这一点)。就我们所见,我们并没有改变我们的方法,只是我们确实希望在多线程上下文中使用它(因为它会嵌入到 Web 应用程序中,这一点已向 Artifex 解释过)。 在阅读了 Ghostscript 许可文档并将许可查询转移到 Artifex 之后,我们不知道拥有 DLL 的多线程版本需要商业许可,所以我们只是想了解原因DLL 不适用于并发场景,调查将我们引向这一点,只是询问知识和信息。如果假设从商业角度来观察这个案例,因为我们确实需要 Artifex 的技术支持来实现这一点,当然,我真的理解这些信息不能免费提供给我们,真的。 这是个人观点,但也许建议 Ghostscript 在许可文档中明确说明,如果您计划通过具有多线程功能的 Web 应用程序使用 Ghostscript,则需要修改源代码(涉及到所有要求,例如释放您自己的源代码,与 AGPL 许可证有关),甚至要求获得商业许可证。这应该可以节省研究时间,并帮助未来的用户充分了解他们在这种情况下拥有的替代方案。 请参阅我对第 2 点的评论,“这可能是一个疏忽”。你可以打开一个错误报告.... 是的,我们已经做到了。一旦我们得到答复,我们将再次联系 Artifex 商业部门重新审查此案,甚至考虑其他替代方案,最终将涉及更改文件提供者。

以上是关于如何获得有效的 x64 THREADSAFE Ghostscript DLL的主要内容,如果未能解决你的问题,请参考以下文章

如何验证代理有效

无法获得非常简单的app.yaml设置工作

VB.NET 动态 API 调用 x64

PHP Thread Safe和Non ThreadSafe

PHP版本Non Thread Safe和Thread Safe如何选择?区别是什么?

在 x64 架构上获得 psyco 加速?