# EasyClassifyMultiThreadInference

| Support            | ![](assets/images/sample_programs/applies_to/cs.svg)                                                    |
|--------------------|---------------------------------------------------------------------------------------------------------|
| Required licenses  | **EasyClassify**                                                                                        |
| Recommended images | In the Deep Learning Additional Resources, the images from the folder `EasyClassify/MiniWaffles/Images` |
| Location           | `Deep Learning Inspection/EasyClassifyMultiThreadInference`                                             |

#### NOTE
- In C++, the sample `EasySegmentSupervisedMultiThreadInference` illustrates a multithread inference for **EasySegment Supervised**.
- In Qt, the sample `EasyLocateMultiThreadInference` illustrates a multithread inference for **EasyLocate**.

## Purpose

This sample program demonstrates how to:

- Perform a multithread inference with **EasyClassify**.
- Implement external and internal multithreading.

![](assets/images/sample_programs/deep_learning_easyclassifymultithreadinference.webp)

## Code highlights

1. Launch one acquisition thread running the function `ImageLoop`.
   ```c++
   ThreadParameters param = new ThreadParameters(this, engine.SelectedItem.ToString(), device.SelectedItem.ToString(), precision.SelectedItem.ToString(), (int)internalThreads.Value, (int)batchSize.Value);       
   acquisitionThread = new Thread(ImageLoop);              
   acquisitionThread.Start(param);
   ```
2. The function `ImageLoop` pushes the images into an image queue.
   ```c++
   ImageBatch batch = new ImageBatch(numImagesPerInference);

   for (int j = 0; j < numImagesPerInference; j++)
   {
     batch.Images[j] = new EImageC24();
     batch.Images[j].Load(mainForm.m_images[i + j]);
     batch.ImagesId[j] = i + j;
   }

   // Adds the batch of images to the queue and signals the processing threads about the new data.
   lock (mainForm.locker)
   {
     queue.Enqueue(batch);
     Monitor.PulseAll(mainForm.locker);
   }
   ```
3. The `NumExternalThreads` processing threads are created and run the function `ClassificationLoop`.
   ```c++
   // Create the external threads
   processingThreads = new Thread[((int)externalThreads.Value)];
   for (int i = 0; i < externalThreads.Value; i++)
   {
     processingThreads[i] = new Thread(ClassificationLoop);
     processingThreads[i].Start(param);
   }
   ```
4. The function `ClassificationLoop` invokes a delegate to pass the computed result to the main UI thread.
   ```c++
   // Invoke the delegate with the results for updating the user interface.
   mainForm.Invoke(mainForm.m_classificationFinishedDelegate, batch.ImagesId, result, stopWatch.ElapsedMilliseconds);
   ```

5.The delegate calls the method `ClassificationFinished` that updates the UI to display the result and the processing time for each image.

```none
```c++
public void ClassificationFinished(int[] imagesId, EClassificationResult[] results, long processingTime)
{
  try
  {
    for (int i = 0; i < imagesId.Length; i++)
    {
      m_detectedClasses[imagesId[i]] = results[i].BestLabel;
      m_processingTime[imagesId[i]] = processingTime;
      m_processed += 1;
      listView1.Items[imagesId[i]].SubItems[1].Text = results[i].BestLabel;
      listView1.Items[imagesId[i]].SubItems[2].Text = String.Format("{0} ms for {1} images", processingTime, imagesId.Length);
      listView1.Items[imagesId[i]].SubItems[3].Text = String.Format("{0} ms", processingTime / imagesId.Length);
    }
    ...
  }
}
```
```
