# Threading

> Use ServerTextControl and MailMerge on several threads: thread safety and critical sections, one instance per operation, parallel loops and background work.

- **Product:** TX Text Control .NET Server
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET Server > Performance and Scalability > Threading
- **1737 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/threading/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/threading/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/threading/llms-full.txt

---

In a web application, `ServerTextControl` and `MailMerge` run on many threads at once: every request that creates a document runs on a thread of its own, and a batch job may start more. TX Text Control supports this, with one condition that decides how you write the code and how far it scales: shared resources are protected, so threads can wait for each other. Whether documents are created in request handlers, parallel loops or background services, the same rules decide how to create the instances, how far to parallelize and when to switch to processes.

### How TX Text Control Handles Threads

TX Text Control is thread safe. It protects the resources that all instances in a process share with critical sections, parts of its code that only one thread runs at a time. When several threads need such a resource, they wait for each other. Text Control describes this as safe, but slower for specific applications.

For your application, this means:

- **Threads work in parallel, but not without limit.** Don't expect more threads in one process to make document processing proportionally faster: they meet at the critical sections.
- **Large batches belong in processes.** For merges of hundreds or thousands of documents, Text Control recommends several processes instead of several threads, as [Multiple Processes](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/multiple-processes/llms-full.txt) describes.
- **The members are synchronous.** `Load`, `Save` and the merge methods of `MailMerge` have no asynchronous versions. They occupy the calling thread until they return.

### Create One Instance per Operation

Every piece of code that creates a document creates, initializes and disposes its own `ServerTextControl` inside the method that does the work, as [Create and Dispose Instances](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/creating/#create-and-dispose-instances) describes. Nothing TX Text Control-related is shared between threads. A service class that a controller receives through dependency injection follows the same rule: it creates the instance in its method, not in its constructor, as the `PdfService` of [Use ServerTextControl in Request Handlers](https://docs.textcontrol.com/tx-text-control-dotnet-server/integration/aspnet-core/#use-servertextcontrol-in-request-handlers) does. A `MailMerge` works on the `ServerTextControl` of the same operation, connected through its `TextComponent` property. Instances that are never disposed make `Create` fail after some time on Windows, as [Memory Usage](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/memory-usage/#dispose-every-servertextcontrol) explains.

### Process Documents on Several Threads

The following console program converts all DOCX files of the folder *Documents* to PDF on up to four threads at the same time:

```csharp
using TXTextControl;

string[] files = Directory.GetFiles("Documents", "*.docx");
Directory.CreateDirectory("Output");

ParallelOptions options = new ParallelOptions
{
    // Find the best value with your own documents
    MaxDegreeOfParallelism = 4
};

Parallel.ForEach(files, options, file =>
{
    // Each operation works with an instance of its own
    using (ServerTextControl tx = new ServerTextControl())
    {
        if (!tx.Create())
        {
            throw new InvalidOperationException("ServerTextControl could not be created.");
        }

        try
        {
            tx.Load(File.ReadAllBytes(file), BinaryStreamType.WordprocessingML);
            tx.Save(out byte[] pdf, BinaryStreamType.AdobePDF);

            string target = Path.Combine("Output", Path.GetFileNameWithoutExtension(file) + ".pdf");
            File.WriteAllBytes(target, pdf);
        }
        catch (FilterException exception)
        {
            Console.WriteLine($"{Path.GetFileName(file)}: {exception.Reason}");
        }
    }
});
```

The code works as follows:

- `Parallel.ForEach` runs the conversion for each file on a thread of the .NET thread pool. `MaxDegreeOfParallelism` limits how many conversions run at the same time.
- Each conversion creates, initializes and disposes its own `ServerTextControl`. Nothing TX Text Control-related is shared between the threads.
- [Load](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/servertextcontrol/load-method/llms-full.txt) reads the DOCX data, and [Save](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/servertextcontrol/save-method/llms-full.txt) writes the PDF document into a byte array in the [BinaryStreamType](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/binarystreamtype/enumeration/llms-full.txt) `AdobePDF`.
- A [FilterException](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/filterexception/llms-full.txt) reports a file that couldn't be loaded or saved, and the other files are converted anyway.

Text Control publishes no fixed number of threads or instances for a server. Measure with your own documents: increase `MaxDegreeOfParallelism` as long as the total time goes down, and keep the value at which it stops improving. In a web service, limit the documents that are created at the same time in the same way, as [Keep the Service Responsive](https://docs.textcontrol.com/tx-text-control-dotnet-server/integration/rest-services/#keep-the-service-responsive) recommends.

### Move Long Work Out of the Request

A request thread that creates a document of several seconds is blocked for that time. Accept such jobs, create the documents in a background service and notify the client when they're ready, as [Keep the Service Responsive](https://docs.textcontrol.com/tx-text-control-dotnet-server/integration/rest-services/#keep-the-service-responsive) in REST Services describes. With many concurrent editors, run heavy processing in a separate application, as [Container Scaling](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/container-scaling/llms-full.txt) explains.

### Set the Culture of Each Merge

[MailMerge.MergeCulture](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol-documentserver/mailmerge/mergeculture-property/llms-full.txt) formats numbers and dates in the merged document, and [DataSourceCulture](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol-documentserver/mailmerge/datasourceculture-property/llms-full.txt) parses them in the data. Both default to the culture of the current thread. On a server, that's the culture of whichever thread runs the merge, which may not be the culture of your documents. Set both explicitly in each merge, as [Parse Numbers and Dates With the Right Culture](https://docs.textcontrol.com/tx-text-control-dotnet-server/mail-merge/data-sources/#parse-numbers-and-dates-with-the-right-culture) in Data Sources shows.

### Next Steps

- [Multiple Processes](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/multiple-processes/llms-full.txt): merge large batches in parallel worker processes.
- [Memory Usage](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/memory-usage/llms-full.txt): dispose instances and find those that are left behind.
- [Performance Best Practices](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/best-practices/llms-full.txt): the measures that make document processing faster.
- [Creating Documents](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/creating/llms-full.txt): the lifecycle of a `ServerTextControl` instance.

---

## Nearby

- **Previous:** [Performance and Scalability](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/llms-full.txt)
- **Next:** [Multiple Processes](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/multiple-processes/llms-full.txt)
