Multithreaded

Illustrates how to use PDFDoc locking mechanisms to access the document concurrently. PDFDoc uses a recursive shared lock model. Multiple threads can read the document at the same time, but only one thread can write to the document. A given thread can acquire as many locks of the same type as it wants, in a recursive fashion. Learn more about our Server SDK.

1//---------------------------------------------------------------------------------------
2// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
3// Consult legal.txt regarding legal and license information.
4//---------------------------------------------------------------------------------------
5
6using System;
7using System.Drawing;
8
9using pdftron;
10using pdftron.Common;
11using pdftron.PDF;
12using pdftron.SDF;
13using System.Threading;
14using System.Threading.Tasks;
15using System.Collections.Generic;
16
17namespace PDFDrawTestCS
18{
19 /// <summary>
20 //---------------------------------------------------------------------------------------
21 // The following sample illustrates how to use PDFDoc locking mechanisms to access the document
22 // concurrently. PDFDoc uses a recursive shared lock model. Multiple threads can read the document
23 // at the same time, but only one thread can write to the document. A given thread can acquire
24 // as many locks of the same type as it wants, in a recursive fashion.
25 //
26 // It's important to note that you cannot upgrade a PDFDoc read lock to a write lock. Because of
27 // the nature of the lock, this would cause a deadlock, and is not allowed.
28 //
29 // If a thread attempts to acquire a write lock while holding a read lock, an exception will be
30 // thrown. As a side effect, this means certain PDFNet API calls which implicitly acquire a write
31 // lock on the document will throw an exception if called while holding a read lock. The API
32 // documents which methods acquire a write lock on the document.
33 //
34 // For more information on document locking in PDFNet, please consult the following knowledge base
35 // article: https://groups.google.com/forum/#!topic/pdfnet-sdk/pDZsqrjCEdg
36 //---------------------------------------------------------------------------------------
37
38 class Class1
39 {
40 private static pdftron.PDFNetLoader pdfNetLoader = pdftron.PDFNetLoader.Instance();
41 static Class1() {}
42
43 /// <summary>
44 /// A static method for rasterizing a given page to a file.
45 /// </summary>
46 static void DoDraw(PDFDoc doc, Page pg, string output_path)
47 {
48 //acquire a read lock, since we will be accessing the document.
49 doc.LockRead();
50
51 //Acquiring a write lock when holding a read lock is illegal,
52 //and would cause an exception to be thrown:
53 //doc.Lock();
54
55 //draw the page
56 using (PDFDraw draw = new PDFDraw())
57 {
58 draw.SetDPI(92);
59 draw.Export(pg, output_path);
60 Console.WriteLine("Rendered page: Result saved in {0}", output_path);
61 }
62
63 //release the read lock
64 doc.UnlockRead();
65 }
66
67 /// <summary>
68 /// The main entry point for the application.
69 /// </summary>
70 static void Main(string[] args)
71 {
72 // The first step in every application using PDFNet is to initialize the
73 // library and set the path to common PDF resources. The library is usually
74 // initialized only once, but calling Initialize() multiple times is also fine.
75 PDFNet.Initialize(PDFTronLicense.Key);
76
77 // Relative path to the folder containing test files
78 string input_path = "../../../../TestFiles/";
79 string output_path = "../../../../TestFiles/Output/";
80
81 //Example - Exporting images of each page in the document in parallel,
82 // and annotating the document in the main thread.
83 try
84 {
85 // Open the PDF document.
86 using (PDFDoc doc = new PDFDoc(input_path + "newsletter.pdf"))
87 {
88 // Lock the document, since we are going to annotate it in this thread.
89 doc.Lock();
90
91 // Initialize the security handler, in case the PDF is encrypted.
92 doc.InitSecurityHandler();
93
94 List<Task> tasks = new List<Task>();
95
96 // Iterate through each page in the document
97 for (PageIterator itr=doc.GetPageIterator(); itr.HasNext(); itr.Next())
98 {
99 //note that locking a second time does not cause a deadlock:
100 doc.Lock();
101
102 // You can acquire a read lock while holding a write lock:
103 doc.LockRead();
104 doc.UnlockRead();
105
106 // Choose an output path for this page
107 string page_output_path = output_path + "newsletter_" + itr.GetPageNumber() + ".png";
108
109 // Create an asynchronous task to draw the page
110 Page pg = itr.Current();
111 Task t = new Task(() => DoDraw(doc, pg, page_output_path));
112 // Start the Task (although it won't be able to access the document, since we have a write lock)
113 t.Start();
114 // Add it to our list of Tasks so we can Wait() for it later.
115 tasks.Add(t);
116
117 Console.WriteLine("Adding stamp to PDFDoc, page " + itr.GetPageNumber());
118
119 // Create a stamp annotation (See AnnotationTest for more details)
120 pdftron.PDF.Annots.RubberStamp stamp = pdftron.PDF.Annots.RubberStamp.Create(doc.GetSDFDoc(), new Rect(30, 30, 300, 200));
121 stamp.SetIcon("Approved");
122 itr.Current().AnnotPushBack(stamp);
123
124 // Releasing the lock decrements our lock count,
125 // but the thread still holds a write lock on the document:
126 doc.Unlock();
127 }
128
129 // Now we release the write lock, and the
130 // PDFDraw tasks can begin execution
131 doc.Unlock();
132
133 // Wait for the PDFDraw tasks to complete.
134 foreach (Task t in tasks)
135 {
136 t.Wait();
137 }
138 }
139 }
140 catch (PDFNetException e)
141 {
142 Console.WriteLine(e.Message);
143 }
144 PDFNet.Terminate();
145 }
146 }
147}

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales