46

请耐心等待我的新手问题..

我试图使用ghostscript、ASP.NET和C#将PDF转换为PNG。但是,我还读到 ghostscript 不是线程安全的。所以我的问题是:

  1. 实际上,“ghostscript 不是线程安全的”到底是什么意思?如果我在一个有许多并发用户同时访问它的实时 ASP.NET(aspx) Web 应用程序中使用它会有什么影响?

  2. 我还从另一个网站上读到了 ghostscript ver 的主要功能。8.63 是多线程渲染。这是否意味着我们的线程安全问题现在已经解决了?现在ghostscript线程安全吗?

  3. 我还在评估来自 PDFTron 的 PDF2Image,它应该是线程安全的。但是每个 CPU 许可证并不便宜。是否值得为“线程安全”与“不安全”支付额外的费用?

4

7 回答 7

39

很难提出每个人都同意的精确技术定义。

非正式地,“线程安全”仅仅意味着“当从多个线程调用时表现得相当好”。当从多个线程调用时,该对象不会崩溃或产生疯狂的结果。

如果您打算进行涉及特定对象的多线程编程,您实际上需要回答的问题是“对象期望的线程模型是什么?”

有很多不同的线程模型。例如,“自由线程”模型是“从任何线程做任何你想做的事;对象会处理它”。这是最容易处理的模型,也是对象提供者最难提供的模型。

另一方面是“单线程”模型——所有对象的所有实例都必须从单个线程访问。

然后中间有一堆东西。“公寓线程”模型是“您可以在两个不同的线程上创建两个实例,但是用于创建实例的任何线程都是您必须始终用于调用该实例上的方法的线程”。

“租用线程”模型是“您可以在两个不同的线程上调用一个实例,但您有责任确保没有两个线程同时这样做”。

等等。在您尝试针对它编写线程代码之前,找出您的对象期望的线程模型。

于 2010-03-09T21:10:57.943 回答
25

例如,鉴于 Collection 不是威胁安全的:

var myDic = new Dictionary<string, string>();

在多线程环境中,这将抛出:

string s = null;
if (!myDic.TryGetValue("keyName", out s)) {
    s = new string('#', 10);
    myDic.Add("keyName", s);
}

当一个线程试图将 KeyValuePair 添加到字典 myDic 中时,另一个线程可能会 TryGetValue()。由于Collection不能同时读写,会出现Exception。

但是,另一方面,如果您尝试以下操作:

// Other threads will wait here until the variable myDic gets unlocked from the preceding thread that has locked it.
lock (myDic) {
    string s = null;
    if (!myDic.TryGetValue("keyName", out s)) {
        s = new string('#', 10);
        myDic.Add("keyName", s);
    }
} // The first thread that locked the myDic variable will now release the lock so that other threads will be able to work with the variable.

然后突然之间,第二个线程试图获得相同的“keyName”键值将不必将它添加到字典中,因为第一个线程已经添加了它。

所以简而言之,线程安全意味着一个对象支持同时被多个线程使用,或者会为你适当地锁定线程,而不必担心线程安全。

2.我不认为 GhostScript 现在是线程安全的。它主要使用多个线程来执行其任务,因此这使其提供了更高的性能,仅此而已。

3.根据您的预算和要求,这可能是值得的。但是如果你围绕包装器构建,你可能只能在方便的地方使用 lock() ,或者如果你自己不使用多线程,那么绝对不值得为线程安全付费。这仅意味着如果您的应用程序使用多线程,那么您将不会遭受库不是线程安全的后果。除非你真的多线程,否则不值得为线程安全库付费。

于 2010-03-09T21:04:10.347 回答
11

我是 Ghostscript 开发人员,不会重复有关线程安全的一般理论。
我们一直在努力让 GS 成为线程安全的,以便可以在单个进程中使用 gsapi_new_instance 创建多个“实例”,但我们还没有完成这一点(包括我们对此的 QA 测试)。
然而,图形库是线程安全的,多线程渲染依赖于此,允许我们生成多个线程来并行渲染显示列表中的波段。多线程渲染已经过大量 QA 测试,并被许多商业许可证持有者用于提高多核 CPU 的性能。

您可以打赌,我们将在最终支持多个 GS 实例时宣布。大多数想要从需要多个实例的应用程序中使用当前 GS 的人都会为每个实例生成单独的进程,因此 GS 不需要是线程安全的。GS 可以运行由参数列表选项确定的作业,或者 I/O 可以通过管道传入/传出进程以提供数据并收集输出。

于 2011-06-26T04:41:43.203 回答
10

1)这意味着如果您在多个线程之间共享相同的 Ghostscript 对象或字段,它将崩溃。例如:

private GhostScript someGSObject = new GhostScript();
...
// Uh oh, 2 threads using shared memory. This can crash!
thread1.Use(someGSObject);
thread2.Use(someGSObject);

2) 我不这么认为——多线程渲染表明 GS 在内部使用多个线程进行渲染。它没有解决 GS 在多线程中使用不安全的问题。

3) 里面有问题吗?

为了使 GhostScript 线程安全,请确保一次只有 1 个线程在访问它。你可以通过锁来做到这一点:

lock(someObject)
{
   thread1.Use(someGSObject);
}
lock(someObject)
{
   thread2.Use(someGSObject);
}
于 2010-03-09T20:47:25.513 回答
3

如果您使用 shell 对象中的 ghostscript(即运行命令行来处理文件),您将不会被线程问题所困扰,因为每个运行的实例都将在服务器上的不同进程中运行。您需要注意的地方是,当您使用 C# 处理 PDF 的 dll 时,需要同步该代码以防止两个线程同时执行相同的代码。

于 2010-03-09T20:52:07.530 回答
2
  1. 线程安全基本上意味着一段代码即使被多个线程访问也能正常运行。如果在线程应用程序中使用非线程安全代码,可能会出现多个问题。最常见的问题是死锁。然而,还有更多的恶意问题(竞争条件),这可能是一个更大的问题,因为众所周知,线程问题很难调试。

  2. 不,多线程渲染只是意味着 GS 将能够更快地渲染,因为它使用线程来渲染(理论上,无论如何 - 在实践中并不总是如此)。

  3. 这真的取决于你想用你的渲染器做什么。如果您打算使用多个线程访问您的应用程序,那么,是的,您需要担心它是线程安全的。否则,这没什么大不了的。

于 2010-03-09T20:51:31.730 回答
1

一般来说,这是一个模棱两可的术语。

线程安全可能处于概念级别,您可以正确同步共享数据。这通常是图书馆作者的意思。

有时,这意味着并发是在语言级别定义的。即语言的内存模型支持并发。这很棘手!因为作为库编写者,您无法生成并发库,因为该语言无法保证需要使用的许多基本原语。这比库用户更关心编译器编写者。从这个意义上说,C# 是线程安全的。

我知道我没有直接回答您的问题,但希望对您有所帮助。

于 2010-03-09T20:50:30.547 回答