[Back to Blog](/blog) # Teigha Multithreading Low-Level API (Part 2 of 4)

Andrew Markovich February 01, 2018 [\#performance](/blog/tag/performance) [\#Example](/blog/tag/example) [\#getting started](/blog/tag/getting-started)

<a class="a2a_button_facebook"></a><a class="a2a_button_twitter"></a><a class="a2a_button_linkedin"></a>

This article is part of a series about the low-level API used for multithreading. For the first article, see [Part 1](https://www.opendesign.com/blog/2018/january/teigha-multithreading-low-level-api-part-1-4).

#### Built-in Teigha mutex objects

Teigha Kernel provides cross-platform implementation of mutex objects. For a description of mutex (MUTual EXclusion) objects, see [Wikipedia](https://en.wikipedia.org/wiki/Mutual_exclusion).

Mutex objects are wrapped in the OdMutex class. This class contains only two methods:

```
void lock();
void unlock();

```

The OdMutex::lock method can be called at the beginning of a critical section that, for example, contains shared resources accessible from multiple threads. The OdMutex::unlock method must be called at the end of the critical section. The OdMutex::lock/OdMutex::unlock methods represent scopes for shared resource access, so they should always be called in a pair. If the OdMutex::unlock method is not called after using the OdMutex::lock method, the code section is kept in a locked state infinitely and the application will enter into an infinite loop. When the thread calls the OdMutex::unlock method it opens the gates for other threads that are waiting inside their OdMutex::lock method calls. Mutex objects are re-enterable, which means that the same tread that has a locked mutex can enter into a locked section again many times, but of course, after each subsequent entrance it must call mutex unlock, which will reduce the number of thread entrances in the critical section; only a final OdMutex::unlock method call will unlock critical code sections for other threads.

To simplify working with mutex objects, the OdMutexAutoLock class can be used. It is simply a call to the OdMutex::lock method in a constructor and to the OdMutex::unlock method in a destructor; this guarantees that the lock/unlock methods pair is called together and the developer doesn’t forget to call mutex unlock when leaving a critical section.

#### Example of using mutex objects

To demonstrate using mutex objects, we will extend our multithreaded image processing example from [Part 1](https://www.opendesign.com/blog/2018/january/teigha-multithreading-low-level-api-part-1-4) in this series of articles. We will add a new ExampleMtStringAccumulator class, which accumulates output text strings from multiple threads into one large text string:

```
// Example of multithread strings accumulator invoking mutex object
class ExampleMtStringAccumulator
{
  protected:
    OdString m_outputString;
    OdMutex m_mutex;
  public:
    ExampleMtStringAccumulator() {}
    ~ExampleMtStringAccumulator() {}
    void addString(const OdString &str)
    {
      TD_AUTOLOCK(m_mutex)
      m_outputString += str;
    }
    const OdString &getString() { return m_outputString; }
};

```

Since the ExampleMtStringAccumulator::addString method will be called from multiple threads, to avoid conflicts between threads during string concatenation we will secure the string concatenation operation using a mutex object. TD\_AUTOLOCK macros simply invoke the OdMutexAutoLock class for multithreaded Teigha configuration, so it is used here to simplify the final code. Alternatively we can use the OdMutexAutoLock class as-is:

```
OdMutexAutoLock autoLock(m_mutex);

```

Now we construct an instance of the ExampleMtStringAccumulator class in our main example function:

```
// Multithread output strings accumulator
ExampleMtStringAccumulator stringsAccum;

```

Extend the ProcessImageCaller class to output scanline numbers that it processed through the ExampleMtStringAccumulator class:

```
// Thread running method implementation
class ProcessImageCaller : public OdRxObject
{
  OdSmartPtr<ProcessedRasterImage> m_pProcImage;
  OdUInt32 m_scanLineFrom, m_nScanLines;
  ExampleMtStringAccumulator *m_pOutput;
  public:
    ProcessImageCaller *setup(ProcessedRasterImage *pProcImage, OdUInt32 scanLineFrom, OdUInt32 nScanLines)
    { m_pProcImage = pProcImage; m_scanLineFrom = scanLineFrom; m_nScanLines = nScanLines;
      return this; }
    static DWORD WINAPI entryPoint(LPVOID pArg)
    {
      ::odThreadsCounter().startThread();
      ProcessImageCaller *pCaller = (ProcessImageCaller*)pArg;
      pCaller->m_pProcImage->process(pCaller->m_scanLineFrom, pCaller->m_nScanLines);
      pCaller->m_pOutput->addString(OdString().format(OD_T("Thread processed scanlines from %u to %u\n"),
                                    (unsigned)pCaller->m_scanLineFrom, (unsigned)(pCaller->m_scanLineFrom + pCaller->m_nScanLines - 1)));
      ::odThreadsCounter().stopThread();
      return EXIT_SUCCESS;
    }
    ProcessImageCaller *run(SimpleWinThreadsPool &threadPool, ExampleMtStringAccumulator *pOutput)
    {
      m_pOutput = pOutput;
      threadPool.runNewThread(entryPoint, this, ThreadsCounter::kNoAttributes);
      return this;
    }
};

```

Now we can pass our ExampleMtStringAccumulator class instance into each ProcessImageCaller instance and output the accumulated string to the console after all treads are completed:

```
// Run threads for raster image processing
const OdUInt32 nScanlinesPerThread = pProcImage->pixelHeight() / 4;
for (OdUInt32 nThread = 0; nThread < 4; nThread++)
{
  OdUInt32 nScanlinesPerThisThread = nScanlinesPerThread;
  if (nThread == 3) // Height can be not divided by 2, so last thread can have one scanline less.
    nScanlinesPerThisThread = pProcImage->pixelHeight() - nScanlinesPerThread * 3;
  lockedObjects.push_back(
    OdRxObjectImpl<ProcessImageCaller>::createObject()->
      setup(pProcImage, nScanlinesPerThread * nThread, nScanlinesPerThisThread)->
        run(winThreadPool, &stringsAccum));
}

// Wait for threads completion
winThreadPool.wait();
lockedObjects.clear();

// Output accumulated string
odPrintConsoleString(stringsAccum.getString());

```

Final output will look like this:

4 files loaded and rendered in 0.421743 seconds  
Thread processed scanlines from 768 to 1023  
Thread processed scanlines from 512 to 767  
Thread processed scanlines from 0 to 255  
Thread processed scanlines from 256 to 511  
Final raster image processed in 0.583598 seconds

Watch for another article coming soon about working with the built-in Teigha Thread ID accessor and using the multithreading low-level API.

## Get started today

**Try ODA software free for 60 days.  
No risk, no credit card required.**

[Try for Free](https://www.opendesign.com/free-trial)
