API Reference > C API Examples > Multithread.c

Multithread.c
The multithread.c example program is for use on the Linux platform.
This sample program demonstrates the use of multiple eduction sessions associated with a single eduction engine running in parallel.
This program takes arguments of the names of the text files to process. The program has the following stages:
1.
2.
3.
*
*
*
4.
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <malloc.h>
#include <string.h>
#include <pthread.h>
#include <edk.h>
 
/*
 * Create an app that uses multiple sessions in parallel
 * Number of sessions depends on the number of input files
 */
 
// Data to pass to each worker thread
typedef struct thread_data
{
   char* file;
      EdkEngineHandle engine;
} t_thread_data;
 
// The worker thread function
// Creates a session using the engine handle
// Processes the the input file
static void* WorkProc(void* pvArgs)
{
   t_thread_data* p = (t_thread_data*)pvArgs;
   EdkEngineHandle engine = p->engine;
   char* file = p->file;
   size_t bytesRead;
   char* buf;
   struct stat fnInfo;
 
   if (stat(file, &fnInfo)) {
      printf("Unable to stat input file.\n");
      return NULL;
   }
   size_t fileSize = fnInfo.st_size;
   if (!fileSize)
   {
      printf("File size of input file is zero!\n");
      return NULL;
   }
 
   FILE *f;
   f = fopen(file, "rb");
   if (!f)
   {
      printf("Can't open input file!\n");
      return NULL;
   }
 
   // Read input file to buffer
   // Note that the input must be UTF-8 encoded.
   buf = (char*)malloc(fileSize * sizeof(char));
   bytesRead = fread(buf, 1, fileSize, f);
   if (bytesRead < fileSize) {
      fclose(f);
      f = NULL;
      printf("Unable to read input file!\n");
      return NULL;
   }
 
   // Create a session and process the input file
   EdkError error;
   EdkSessionHandle session = NULL;
   if (EdkSuccess != (error = EdkSessionCreate(engine, &session)))
   {
      printf("Error: Unable to create session, erro code = %d\n", error);
      return NULL;
   }
   if (EdkSuccess != (error = EdkAddInputText(session, buf, bytesRead, true)))
   {
      printf("Unable to add input text, error code = %d\n", error);
      return NULL;
   }
   else
   {
      while(EdkSuccess == EdkGetNextMatch(session))
      {
         // For each match found, do this ...
         const char* szMatch = NULL;
         EdkGetMatchText(session, &szMatch);
         printf("Match found: %s\n", szMatch);
      }
   }
 
   // Destroy the session and exit when done
   EdkSessionDestroy(session);
   session = NULL;
 
   free(buf);
   return NULL;
}
 
// Main function
// Reads arguments from command line as input files
// Creates one thread to process each input file
int main(int argc, char **argv)
{
   char *license;
   struct stat fnLicense;
   off_t len;
   FILE *f;
   size_t itemsRead;
 
   // Input files are specified at the command line
   // One thread will be created to process every input file
   if (argc <= 1) {
      printf("No input file specified.\n");
      return -1;
   }
 
   // Licensing
   if (stat("licensekey.dat", &fnLicense)) {
      printf("Unable to stat license file.\n");
      return -1;
   }
   len = fnLicense.st_size;
   if (!len) {
      printf("Zero byte file size for license file.\n");
      return -1;
   }
   f = fopen("licensekey.dat", "rb");
   if (!f) {
      printf("Unable to open license file.\n");
      return -1;
   }
   license = (char*)malloc(len+1);
   itemsRead = fread(license, 1, len, f);
   *(license+len) = '\0';
   fclose(f);
   if (itemsRead < (size_t)len) {
      free(license);
      printf("Unable to read license.\n");
      return -1;
   }
   if (!license) {
      return -1;
   }
   printf("INFO: License read.\n");
 
   // Create the eduction engine
   EdkError error;
   EdkEngineHandle engine = NULL;
   if (EdkSuccess != (error = EdkEngineCreate(&engine)))
   {
      printf("Error: Can't create engine, error code = %d.\n", error);
      return -1;
   }
 
   if (EdkSuccess != (error = EdkSetLicenseKey(engine, license))) {
      printf("Error: Can't set license key, error code = %d.\n", error);
      free(license);
      EdkEngineDestroy(engine);
      return -1;
   }
   printf("INFO: License validated.\n");
   free(license);
 
   // Load the resource file - change if necessary
   if (EdkSuccess != (error = EdkLoadResourceFile(engine, "company_eng.ecr")))
   {
      printf("Error: Can't load resource file, error code = %d.\n", error);
      EdkEngineDestroy(engine);
      return -1;
   }
   printf("INFO: Resource file loaded.\n");
 
   // Add target entity - change if necessary
   if (EdkSuccess != (error = EdkAddTargetEntity(engine, "company/name/eng")))
   {
      printf("Error: Can't add entity, error cdoe = %d.\n", error);
      EdkEngineDestroy(engine);
      return -1;
   }
   printf("INFO: Entity added.\n");
 
   // Prepare the worker threads
   size_t nThreads = argc - 1;
   pthread_t* threadId = (pthread_t*)calloc(nThreads, sizeof(pthread_t));
   void* tmp = calloc(nThreads, sizeof(t_thread_data));
   t_thread_data* threadData = (t_thread_data*)tmp;
   int ii = 0;
   pthread_attr_t attr;
   pthread_attr_init(&attr);
   pthread_attr_setstacksize(&attr, 128000);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 
   // Start the threads
   // Each thread uses a session to process an input file
   for(ii=0;ii<nThreads;ii++)
   {
      threadData[ii].engine = engine;
      threadData[ii].file = argv[ii + 1];
      pthread_create(&threadId[ii], &attr, WorkProc, (void*)&threadData[ii]);
   }
 
   // Join the threads when done
   for (ii = 0; ii < nThreads; ii++)
   {
      if (threadId[ii])
      {
         void *pvres;
         pthread_join(threadId[ii], &pvres);
      }
   }
 
   free(threadId);
   free(threadData);
   EdkEngineDestroy(engine);
   printf("INFO: Done\n");
 
   return 1;
}