什么“线程安全”真正意味着......在实践中

时间:2010-03-09 20:44:52

标签: c# asp.net multithreading thread-safety ghostscript

请忍受我的新手问题..

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

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

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

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

7 个答案:

答案 0 :(得分:33)

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

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

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

有许多不同的线程模型。例如,“自由线程”模型是“从任何线程做任何你想做的事情;对象将处理它。”这是您处理的最简单的模型,也是对象提供者最难提供的模型。

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

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

“rental threaded”模型是“你可以在两个不同的线程上调用一个实例,但你有责任确保没有两个线程同时执行此操作”。

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

答案 1 :(得分:22)

例如,鉴于集合不是threasafe:

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()。由于无法同时读取和写入集合,因此会发生异常。

然而,另一方面,如果您尝试这样做:

// 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。根据您的预算和要求,这可能是值得的。但是如果你围绕包装器构建,你可能只能在方便的地方锁定(),或者如果你自己不使用多线程,那么绝对不值得为线程安全付费。这仅表示如果您的应用程序使用多线程,那么您将不会遭受库不是线程安全的后果。除非你真的多线程,否则不值得为线程安全库付费。

答案 2 :(得分: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线程安全,请确保一次只有一个线程正在访问它。你可以通过锁来做到这一点:

lock(someObject)
{
   thread1.Use(someGSObject);
}
lock(someObject)
{
   thread2.Use(someGSObject);
}

答案 3 :(得分:10)

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

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

答案 4 :(得分:3)

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

答案 5 :(得分:2)

  1. 线程安全基本上意味着即使在多个线程访问时,一段代码也能正常运行。如果在线程应用程序中使用非线程安全代码,则可能会出现多个问题。最常见的问题是死锁。然而,还有更多的恶意问题(竞争条件),这可能是一个更大的问题,因为线程问题非常难以调试。

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

  3. 这实际上取决于您想要使用渲染器的内容。如果您要使用多个线程访问您的应用程序,那么,是的,您需要担心它是线程安全的。否则,这不是什么大问题。

答案 6 :(得分:1)

一般来说,这是一个含糊不清的术语。

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

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

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