什么“线程安全”真的意味着…在实际中

请忍受我的新手问题

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

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

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

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

鉴于一个集合,例如,不是threasafe:

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

在multithreading环境中,这将抛出:

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

当一个线程正在尝试将KeyValuePair添加到字典myDic时,另一个可能TryGetValue()。 由于集合不能同时读写,就会出现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”键值将不必将其添加到字典,因为第一个线程已经添加它。

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

2.我不认为GhostScript现在是线程安全的。 主要是使用多个线程来执行任务,这使得它可以提供更高的性能。

3.根据您的预算和您的要求,这可能是值得的。 但是,如果围绕wrapper构build,也许只能locking()方便的地方,或者如果你自己不使用multithreading,绝对不值得使用thread安全。 这意味着只有当你的应用程序使用multithreading的时候,你才不会因为一个库不是线程安全的后果。 除非你真的multithreading,否则不值得为线程安全库付钱。

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

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

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

有一堆不同的线程模型。 例如,“免费线程”模式是“任何线程都可以做任何事情;对象将会处理它”。 这是你处理的最简单的模型,对象提供者最难提供。

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

然后中间有一堆东西 “单元线程”模型是“你可以在两个不同的线程上创build两个实例,但是无论你使用哪个线程来创build实例,都必须使用该线程来调用该实例的方法”。

“租用线程”模式是“你可以在两个不同的线程上调用一个实例,但你有责任确保没有两个线程同时进行。

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

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

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

2)我不这么认为 – multithreading渲染build议GS在内部使用多个线程来渲染。 它没有解决GS从多个线程使用不安全的问题。

3)那里有问题吗?

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

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

我是一个Ghostscript开发者,不会重复关于线程安全的一般理论。
我们一直在努力使GS成为线程安全的,从而可以在单个进程中使用gsapi_new_instance创build多个“实例”,但是我们还没有完成这个任务(包括我们对此的QAtesting)。
但是,graphics库是线程安全的,multithreading渲染依赖于这个,允许我们产生多个线程并行显示列表。 multithreading渲染已经过许多QAtesting,许多商业许可证使用它来提高多核CPU的性能。

你可以打赌,我们会宣布什么时候我们终于支持GS的多个实例。 大多数想要从需要多个实例的应用程序使用当前GS的人为每个实例产生不同的进程,以便GS不需要是线程安全的。 GS可以运行由参数列表选项确定的任务,或者可以通过input/输出进程来提供数据和收集输出。

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

  1. 线程安全基本上意味着一段代码即使在multithreading访问时也能正常工作。 如果在线程应用程序中使用非线程安全代码,则可能会出现多个问题。 最常见的问题是死锁。 然而,更棘手的问题(竞争条件)可能更成为一个问题,因为线程问题非常难以debugging。

  2. 没有。multithreading渲染只是意味着GS将能够更快渲染,因为它使用线程渲染(无论如何 – 在实践中并非总是如此)。

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

总的来说,这是一个含糊的术语。

线程安全可以在概念层面上,在那里你有共享数据的正确同步。 这通常是图书馆作者的意思。

有时候,这意味着在语言层面定义了并发性。 即语言的内存模型支持并发。 这是棘手的! 因为作为一个库作家,你不能产生并发库,因为这个语言不能保证需要使用的许多基本原语。 这比编译器用户更关心编译器编写者。 C#在这个意义上是线程安全的。

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