/// <summary>
        /// Call if one worker is available
        /// </summary>
        /// <param name="workerUrl">worker url</param>
        /// <returns></returns>
        public bool FinishProcessing(string workerUrl, WorkStatus workerStatus)
        {
            TestFrozenC();
            jobsAssigmentMutex.WaitOne();

            foreach (WorkStatus iWorkStatus in jobsAssigment)
            {
                if (iWorkStatus.getWorkerId() == workerStatus.getWorkerId() && iWorkStatus.getBeginIndex() == workerStatus.getBeginIndex())
                {
                    iWorkStatus.setLastModification(workerStatus.getLastModification());
                    iWorkStatus.setNumberLinesComputed(workerStatus.getNumberLinesComputed());
                    iWorkStatus.setTotalNumberOfLines(workerStatus.getTotalNumberLines());
                    iWorkStatus.setWorkerId(workerStatus.getWorkerId());

                    //Console.WriteLine("FINISH " + workerStatus.getWorkerId());
                    break;
                }
            }

            jobsAssigmentMutex.ReleaseMutex();

            availableWorkerToJobMutex.WaitOne();
            bool exists = availableWorkerToJob.Contains(workerUrl);

            availableWorkerToJobMutex.ReleaseMutex();

            if (!exists)
            {
                availableWorkerToJobMutex.WaitOne();
                availableWorkerToJob.Add(workerUrl);
                availableWorkerToJobMutex.ReleaseMutex();

                queueWorkersSemaphore.Release(1);
            }



            return(true);
        }
        // =============================================
        // Threads Section
        // =============================================

        /// <summary>
        /// Async method to keep tracking of alive workers
        /// </summary>
        public void IsAliveAsync()
        {
            while (!jobDone)
            {
                TestFrozenC();

                //Is alive interval
                Thread.Sleep(2000);

                //Create a copy of the workersUrl
                workersIDUrlMutex.WaitOne();
                HashSet <KeyValuePair <int, string> > clonedWorkersUrl = new HashSet <KeyValuePair <int, string> >(workersIDUrl);
                workersIDUrlMutex.ReleaseMutex();

                jobsAssigmentMutex.WaitOne();
                HashSet <WorkStatus> clonedJobAssigments = new HashSet <WorkStatus>(jobsAssigment);
                jobsAssigmentMutex.ReleaseMutex();

                foreach (KeyValuePair <int, string> worker in clonedWorkersUrl)
                {
                    //Get the worker
                    IWorker workerObj = (IWorker)Activator.GetObject(typeof(IWorker), worker.Value);

                    try {
                        //Retrive the workStatus of the worker
                        WorkStatus workerStatus = workerObj.IsAlive(clonedWorkersUrl, clonedJobAssigments);


                        //Update the workStatus of that worker

                        jobsAssigmentMutex.WaitOne();
                        foreach (WorkStatus iWorkStatus in jobsAssigment)
                        {
                            if (iWorkStatus.getWorkerId() == workerStatus.getWorkerId() && iWorkStatus.getBeginIndex() == workerStatus.getBeginIndex())
                            {
                                iWorkStatus.setLastModification(workerStatus.getLastModification());
                                iWorkStatus.setNumberLinesComputed(workerStatus.getNumberLinesComputed());
                                iWorkStatus.setTotalNumberOfLines(workerStatus.getTotalNumberLines());
                                iWorkStatus.setWorkerId(workerStatus.getWorkerId());

                                //Console.WriteLine("isalive"  + workerStatus.getWorkerId());

                                break;
                            }
                        }
                        jobsAssigmentMutex.ReleaseMutex();

                        //TODO: test if the worker is too slow
                    } catch (Exception) { //The worker didn't anwser
                        Console.WriteLine("***************" + worker.Value + "dead");

                        //Remove the worker from the workersList
                        workersIDUrlMutex.WaitOne();
                        workersIDUrl.Remove(worker);
                        workersIDUrlMutex.ReleaseMutex();

                        //Removes all the works not done and assigned to it
                        jobsAssigmentMutex.WaitOne();
                        foreach (WorkStatus iWorkStatus in jobsAssigment)
                        {
                            if (iWorkStatus.getWorkerId() == worker.Key && !iWorkStatus.isWorkCompleted())
                            {
                                iWorkStatus.removeWorker();
                            }
                        }
                        jobsAssigmentMutex.ReleaseMutex();


                        //Remove from available worker
                        availableWorkerToJobMutex.WaitOne();
                        availableWorkerToJob.Remove(worker.Value);
                        availableWorkerToJobMutex.ReleaseMutex();
                    }
                }
            }
        }