下面是线程池的类,下面是threadpool.h文件
1 /* 2 * threadpool.h 3 * 4 * Created on: 2015年1月8日 5 * Author: xk 6 */ 7 8 #ifndef THREADPOOL_THREADPOOL_H_ 9 #define THREADPOOL_THREADPOOL_H_ 10 /* 11 Thread Pool implementation for unix / linux environments 12 Copyright (C) 2008 Shobhit Gupta 13 14 This program is free software: you can redistribute it and/or modify 15 it under the terms of the GNU General Public License as published by 16 the Free Software Foundation, either version 3 of the License, or 17 (at your option) any later version. 18 19 This program is distributed in the hope that it will be useful, 20 but WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 GNU General Public License for more details. 23 24 You should have received a copy of the GNU General Public License 25 along with this program. If not, see <http://www.gnu.org/licenses/>. 26 */ 27 #include <unistd.h> 28 #include <pthread.h> 29 #include <semaphore.h> 30 #include <iostream> 31 #include <vector> 32 using namespace std; 33 /* 34 WorkerThread class 35 This class needs to be sobclassed by the user. 36 */ 37 class WorkerThread{ 38 public: 39 int id; 40 41 unsigned virtual executeThis() 42 { 43 return 0; 44 } 45 46 WorkerThread(int id) : id(id) {} 47 virtual ~WorkerThread(){} 48 }; 49 50 /* 51 ThreadPool class manages all the ThreadPool related activities. 52 This includes keeping track of idle threads and ynchronizations between all threads. 53 */ 54 class ThreadPool{ 55 public: 56 ThreadPool(); 57 ThreadPool(int maxThreadsTemp); 58 virtual ~ThreadPool(); 59 60 void destroyPool(int maxPollSecs); 61 62 bool assignWork(WorkerThread *worker); 63 bool fetchWork(WorkerThread **worker); 64 65 void initializeThreads(); 66 67 static void *threadExecute(void *param); 68 69 static pthread_mutex_t mutexSync; 70 static pthread_mutex_t mutexWorkCompletion; 71 72 private: 73 int maxThreads; 74 75 pthread_cond_t condCrit; 76 sem_t availableWork; 77 sem_t availableThreads; 78 79 //WorkerThread ** workerQueue; 80 vector<WorkerThread *> workerQueue; 81 82 int topIndex; 83 int bottomIndex; 84 85 int incompleteWork; 86 87 int queueSize; 88 89 }; 90 91 92 #endif /* THREADPOOL_THREADPOOL_H_ */
下面是threadpool.cpp文件
1 /* 2 * threadpool.cpp 3 * 4 * Created on: 2015年1月8日 5 * Author: xk 6 */ 7 /* 8 Thread Pool implementation for unix / linux environments 9 Copyright (C) 2008 Shobhit Gupta 10 11 This program is free software: you can redistribute it and/or modify 12 it under the terms of the GNU General Public License as published by 13 the Free Software Foundation, either version 3 of the License, or 14 (at your option) any later version. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with this program. If not, see <http://www.gnu.org/licenses/>. 23 */ 24 25 #include <stdlib.h> 26 #include "threadpool.h" 27 28 using namespace std; 29 30 pthread_mutex_t ThreadPool::mutexSync = PTHREAD_MUTEX_INITIALIZER; 31 pthread_mutex_t ThreadPool::mutexWorkCompletion = PTHREAD_MUTEX_INITIALIZER; 32 33 34 35 ThreadPool::ThreadPool() 36 { 37 ThreadPool(2); 38 } 39 40 ThreadPool::ThreadPool(int maxThreads) 41 { 42 if (maxThreads < 1) maxThreads = 1; 43 44 //mutexSync = PTHREAD_MUTEX_INITIALIZER; 45 //mutexWorkCompletion = PTHREAD_MUTEX_INITIALIZER; 46 47 pthread_mutex_lock(&mutexSync); 48 this->maxThreads = maxThreads; 49 this->queueSize = maxThreads; 50 //workerQueue = new WorkerThread *[maxThreads]; 51 workerQueue.resize(maxThreads, NULL); 52 topIndex = 0; 53 bottomIndex = 0; 54 incompleteWork = 0; 55 sem_init(&availableWork, 0, 0); 56 sem_init(&availableThreads, 0, queueSize); 57 pthread_mutex_unlock(&mutexSync); 58 } 59 60 void ThreadPool::initializeThreads() 61 { 62 for (int i = 0; i<maxThreads; ++i) 63 { 64 pthread_t tempThread; 65 pthread_create(&tempThread, NULL, &ThreadPool::threadExecute, (void *) this); 66 //threadIdVec[i] = tempThread; 67 } 68 69 } 70 71 ThreadPool::~ThreadPool() 72 { 73 workerQueue.clear(); 74 } 75 76 77 78 void ThreadPool::destroyPool(int maxPollSecs = 2) 79 { 80 while (incompleteWork>0) 81 { 82 cout << "Work is still incomplete=" << incompleteWork << endl; 83 sleep(maxPollSecs); 84 } 85 cout << "All Done!! Wow! That was a lot of work!" << endl; 86 sem_destroy(&availableWork); 87 sem_destroy(&availableThreads); 88 pthread_mutex_destroy(&mutexSync); 89 pthread_mutex_destroy(&mutexWorkCompletion); 90 91 } 92 93 94 bool ThreadPool::assignWork(WorkerThread *workerThread) 95 { 96 pthread_mutex_lock(&mutexWorkCompletion); 97 incompleteWork++; 98 //cout << "assignWork...incomapleteWork=" << incompleteWork << endl; 99 pthread_mutex_unlock(&mutexWorkCompletion); 100 101 sem_wait(&availableThreads); 102 103 pthread_mutex_lock(&mutexSync); 104 //workerVec[topIndex] = workerThread; 105 workerQueue[topIndex] = workerThread; 106 cout << "Assigning Worker[" << workerThread->id << "] Address:[" << workerThread << "] to Queue index [" << topIndex << "]" << endl; 107 if (queueSize != 1) 108 topIndex = (topIndex + 1) % (queueSize); 109 sem_post(&availableWork); 110 pthread_mutex_unlock(&mutexSync); 111 return true; 112 } 113 114 bool ThreadPool::fetchWork(WorkerThread **workerArg) 115 { 116 sem_wait(&availableWork); 117 118 pthread_mutex_lock(&mutexSync); 119 WorkerThread * workerThread = workerQueue[bottomIndex]; 120 workerQueue[bottomIndex] = NULL; 121 *workerArg = workerThread; 122 if (queueSize != 1) 123 bottomIndex = (bottomIndex + 1) % (queueSize); 124 sem_post(&availableThreads); 125 pthread_mutex_unlock(&mutexSync); 126 return true; 127 } 128 129 void *ThreadPool::threadExecute(void *param) 130 { 131 WorkerThread *worker = NULL; 132 133 while (((ThreadPool *)param)->fetchWork(&worker)) 134 { 135 if (worker) 136 { 137 worker->executeThis(); 138 //cout << "worker[" << worker->id << "] delete address: [" << worker << "]" << endl; 139 delete worker; 140 worker = NULL; 141 } 142 143 pthread_mutex_lock(&(((ThreadPool *)param)->mutexWorkCompletion)); 144 //cout << "Thread " << pthread_self() << " has completed a Job !" << endl; 145 ((ThreadPool *)param)->incompleteWork--; 146 pthread_mutex_unlock(&(((ThreadPool *)param)->mutexWorkCompletion)); 147 } 148 return 0; 149 }
下面是main.cpp文件
1 /* 2 * main.cpp 3 * 4 * Created on: 2015年1月8日 5 * Author: xk 6 */ 7 /* 8 Thread Pool implementation for unix / linux environments 9 Copyright (C) 2008 Shobhit Gupta 10 11 This program is free software: you can redistribute it and/or modify 12 it under the terms of the GNU General Public License as published by 13 the Free Software Foundation, either version 3 of the License, or 14 (at your option) any later version. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with this program. If not, see <http://www.gnu.org/licenses/>. 23 */ 24 25 #include <iostream> 26 #include "threadpool.h" 27 28 using namespace std; 29 30 #define ITERATIONS 200 31 32 class SampleWorkerThread : public WorkerThread 33 { 34 public: 35 int id; 36 37 unsigned virtual executeThis() 38 { 39 // Instead of sleep() we could do anytime consuming work here. 40 //Using ThreadPools is advantageous only when the work to be done is really time consuming. (atleast 1 or 2 seconds) 41 sleep(2); 42 43 return(0); 44 } 45 46 47 SampleWorkerThread(int id) : WorkerThread(id), id(id) 48 { 49 // cout << "Creating SampleWorkerThread " << id << " address=" << this << endl; 50 } 51 52 ~SampleWorkerThread() 53 { 54 // cout << "Deleting SampleWorkerThread " << id << " address=" << this << endl; 55 } 56 }; 57 58 59 int main(int argc, char **argv) 60 { 61 //ThreadPool(N); 62 //Create a Threadpool with N number of threads 63 ThreadPool* myPool = new ThreadPool(25); 64 myPool->initializeThreads(); 65 66 //We will count time elapsed after initializeThreads() 67 time_t t1 = time(NULL); 68 69 //Lets start bullying ThreadPool with tonnes of work !!! 70 for (unsigned int i = 0; i<ITERATIONS; i++){ 71 SampleWorkerThread* myThread = new SampleWorkerThread(i); 72 //cout << "myThread[" << myThread->id << "] = [" << myThread << "]" << endl; 73 myPool->assignWork(myThread); 74 } 75 76 // destroyPool(int maxPollSecs) 77 // Before actually destroying the ThreadPool, this function checks if all the pending work is completed. 78 // If the work is still not done, then it will check again after maxPollSecs 79 // The default value for maxPollSecs is 2 seconds. 80 // And ofcourse the user is supposed to adjust it for his needs. 81 82 myPool->destroyPool(2); 83 84 time_t t2 = time(NULL); 85 cout << t2 - t1 << " seconds elapsed " << endl; 86 delete myPool; 87 88 return 0; 89 }
我是在ubuntu下利用eclipse编译运行的程序,在编译前右击项目->properties->C/C++ Build->Settings->GCC C++ Linker->Librareis,在Librabires(-l)中添加pthread然后编译运行即可
下面是结果
Assigning Worker[0] Address:[0x147bb60] to Queue index [0] Assigning Worker[1] Address:[0x147bb80] to Queue index [1] Assigning Worker[2] Address:[0x147bba0] to Queue index [2] Assigning Worker[3] Address:[0x147bbc0] to Queue index [3] Assigning Worker[4] Address:[0x147bbe0] to Queue index [4] Assigning Worker[5] Address:[0x147bc00] to Queue index [5] Assigning Worker[6] Address:[0x147bc20] to Queue index [6] Assigning Worker[7] Address:[0x147bc40] to Queue index [7] Assigning Worker[8] Address:[0x147bc60] to Queue index [8] Assigning Worker[9] Address:[0x147bc80] to Queue index [9] Assigning Worker[10] Address:[0x147bca0] to Queue index [10] Assigning Worker[11] Address:[0x147bcc0] to Queue index [11] Assigning Worker[12] Address:[0x147bce0] to Queue index [12] Assigning Worker[13] Address:[0x147bd00] to Queue index [13] Assigning Worker[14] Address:[0x147bd20] to Queue index [14] Assigning Worker[15] Address:[0x147bd40] to Queue index [15] Assigning Worker[16] Address:[0x147bd60] to Queue index [16] Assigning Worker[17] Address:[0x147bd80] to Queue index [17] Assigning Worker[18] Address:[0x147bda0] to Queue index [18] Assigning Worker[19] Address:[0x147bdc0] to Queue index [19] Assigning Worker[20] Address:[0x147bde0] to Queue index [20] Assigning Worker[21] Address:[0x147be00] to Queue index [21] Assigning Worker[22] Address:[0x147be20] to Queue index [22] Assigning Worker[23] Address:[0x147be40] to Queue index [23] Assigning Worker[24] Address:[0x147be60] to Queue index [24] Assigning Worker[25] Address:[0x147be80] to Queue index [0] Assigning Worker[26] Address:[0x147bea0] to Queue index [1] Assigning Worker[27] Address:[0x147bec0] to Queue index [2] Assigning Worker[28] Address:[0x147bee0] to Queue index [3] Assigning Worker[29] Address:[0x147bf00] to Queue index [4] Assigning Worker[30] Address:[0x147bf20] to Queue index [5] Assigning Worker[31] Address:[0x147bf40] to Queue index [6] Assigning Worker[32] Address:[0x147bf60] to Queue index [7] Assigning Worker[33] Address:[0x147bf80] to Queue index [8] Assigning Worker[34] Address:[0x147bfa0] to Queue index [9] Assigning Worker[35] Address:[0x147bfc0] to Queue index [10] Assigning Worker[36] Address:[0x147bfe0] to Queue index [11] Assigning Worker[37] Address:[0x147c000] to Queue index [12] Assigning Worker[38] Address:[0x147c020] to Queue index [13] Assigning Worker[39] Address:[0x147c040] to Queue index [14] Assigning Worker[40] Address:[0x147c060] to Queue index [15] Assigning Worker[41] Address:[0x147c080] to Queue index [16] Assigning Worker[42] Address:[0x147c0a0] to Queue index [17] Assigning Worker[43] Address:[0x147c0c0] to Queue index [18] Assigning Worker[44] Address:[0x147c0e0] to Queue index [19] Assigning Worker[45] Address:[0x147c100] to Queue index [20] Assigning Worker[46] Address:[0x147c120] to Queue index [21] Assigning Worker[47] Address:[0x147c140] to Queue index [22] Assigning Worker[48] Address:[0x147c160] to Queue index [23] Assigning Worker[49] Address:[0x147c180] to Queue index [24] Assigning Worker[50] Address:[0x147c1a0] to Queue index [0] Assigning Worker[51] Address:[0x147bd80] to Queue index [1] Assigning Worker[52] Address:[0x147be00] to Queue index [2] Assigning Worker[53] Address:[0x147be20] to Queue index [3] Assigning Worker[54] Address:[0x147be60] to Queue index [4] Assigning Worker[55] Address:[0x147be40] to Queue index [5] Assigning Worker[56] Address:[0x147bdc0] to Queue index [6] Assigning Worker[57] Address:[0x147bda0] to Queue index [7] Assigning Worker[58] Address:[0x147bd60] to Queue index [8] Assigning Worker[59] Address:[0x147bd40] to Queue index [9] Assigning Worker[60] Address:[0x147bd20] to Queue index [10] Assigning Worker[61] Address:[0x147bd00] to Queue index [11] Assigning Worker[62] Address:[0x147bce0] to Queue index [12] Assigning Worker[63] Address:[0x147bcc0] to Queue index [13] Assigning Worker[64] Address:[0x147bca0] to Queue index [14] Assigning Worker[65] Address:[0x147bc80] to Queue index [15] Assigning Worker[66] Address:[0x147bc60] to Queue index [16] Assigning Worker[67] Address:[0x147bc40] to Queue index [17] Assigning Worker[68] Address:[0x147bde0] to Queue index [18] Assigning Worker[69] Address:[0x147bc20] to Queue index [19] Assigning Worker[70] Address:[0x147bc00] to Queue index [20] Assigning Worker[71] Address:[0x147bbe0] to Queue index [21] Assigning Worker[72] Address:[0x147bbc0] to Queue index [22] Assigning Worker[73] Address:[0x147bba0] to Queue index [23] Assigning Worker[74] Address:[0x147bb80] to Queue index [24] Assigning Worker[75] Address:[0x147bb60] to Queue index [0] Assigning Worker[76] Address:[0x147bee0] to Queue index [1] Assigning Worker[77] Address:[0x147bf00] to Queue index [2] Assigning Worker[78] Address:[0x147bec0] to Queue index [3] Assigning Worker[79] Address:[0x147bea0] to Queue index [4] Assigning Worker[80] Address:[0x147bf40] to Queue index [5] Assigning Worker[81] Address:[0x147bf20] to Queue index [6] Assigning Worker[82] Address:[0x147be80] to Queue index [7] Assigning Worker[83] Address:[0x147bf60] to Queue index [8] Assigning Worker[84] Address:[0x147bfa0] to Queue index [9] Assigning Worker[85] Address:[0x147bf80] to Queue index [10] Assigning Worker[86] Address:[0x147bfc0] to Queue index [11] Assigning Worker[87] Address:[0x147c080] to Queue index [12] Assigning Worker[88] Address:[0x147c0c0] to Queue index [13] Assigning Worker[89] Address:[0x147c020] to Queue index [14] Assigning Worker[90] Address:[0x147c040] to Queue index [15] Assigning Worker[91] Address:[0x147c0a0] to Queue index [16] Assigning Worker[92] Address:[0x147c060] to Queue index [17] Assigning Worker[93] Address:[0x147c000] to Queue index [18] Assigning Worker[94] Address:[0x147c0e0] to Queue index [19] Assigning Worker[95] Address:[0x147c100] to Queue index [20] Assigning Worker[96] Address:[0x147bfe0] to Queue index [21] Assigning Worker[97] Address:[0x147c160] to Queue index [22] Assigning Worker[98] Address:[0x147c140] to Queue index [23] Assigning Worker[99] Address:[0x147c180] to Queue index [24] Assigning Worker[100] Address:[0x147c120] to Queue index [0] Assigning Worker[101] Address:[0x147be00] to Queue index [1] Assigning Worker[102] Address:[0x147be20] to Queue index [2] Assigning Worker[103] Address:[0x147be60] to Queue index [3] Assigning Worker[104] Address:[0x147bd80] to Queue index [4] Assigning Worker[105] Address:[0x147c1a0] to Queue index [5] Assigning Worker[106] Address:[0x147bd60] to Queue index [6] Assigning Worker[107] Address:[0x147bdc0] to Queue index [7] Assigning Worker[108] Address:[0x147bda0] to Queue index [8] Assigning Worker[109] Address:[0x147be40] to Queue index [9] Assigning Worker[110] Address:[0x147bd20] to Queue index [10] Assigning Worker[111] Address:[0x147bd40] to Queue index [11] Assigning Worker[112] Address:[0x147bd00] to Queue index [12] Assigning Worker[113] Address:[0x147bca0] to Queue index [13] Assigning Worker[114] Address:[0x147bcc0] to Queue index [14] Assigning Worker[115] Address:[0x147bde0] to Queue index [15] Assigning Worker[116] Address:[0x147bc80] to Queue index [16] Assigning Worker[117] Address:[0x147bc40] to Queue index [17] Assigning Worker[118] Address:[0x147bc60] to Queue index [18] Assigning Worker[119] Address:[0x147bce0] to Queue index [19] Assigning Worker[120] Address:[0x147bc00] to Queue index [20] Assigning Worker[121] Address:[0x147bc20] to Queue index [21] Assigning Worker[122] Address:[0x147bb80] to Queue index [22] Assigning Worker[123] Address:[0x147bba0] to Queue index [23] Assigning Worker[124] Address:[0x147bbc0] to Queue index [24] Assigning Worker[125] Address:[0x147bbe0] to Queue index [0] Assigning Worker[126] Address:[0x147bea0] to Queue index [1] Assigning Worker[127] Address:[0x147bec0] to Queue index [2] Assigning Worker[128] Address:[0x147bee0] to Queue index [3] Assigning Worker[129] Address:[0x147bf40] to Queue index [4] Assigning Worker[130] Address:[0x147be80] to Queue index [5] Assigning Worker[131] Address:[0x147bf20] to Queue index [6] Assigning Worker[132] Address:[0x147bf60] to Queue index [7] Assigning Worker[133] Address:[0x147bf00] to Queue index [8] Assigning Worker[134] Address:[0x147bb60] to Queue index [9] Assigning Worker[135] Address:[0x147bfa0] to Queue index [10] Assigning Worker[136] Address:[0x147bf80] to Queue index [11] Assigning Worker[137] Address:[0x147bfc0] to Queue index [12] Assigning Worker[138] Address:[0x147c0c0] to Queue index [13] Assigning Worker[139] Address:[0x147c040] to Queue index [14] Assigning Worker[140] Address:[0x147c020] to Queue index [15] Assigning Worker[141] Address:[0x147c080] to Queue index [16] Assigning Worker[142] Address:[0x147c060] to Queue index [17] Assigning Worker[143] Address:[0x147c0a0] to Queue index [18] Assigning Worker[144] Address:[0x147c000] to Queue index [19] Assigning Worker[145] Address:[0x147c0e0] to Queue index [20] Assigning Worker[146] Address:[0x147c140] to Queue index [21] Assigning Worker[147] Address:[0x147c160] to Queue index [22] Assigning Worker[148] Address:[0x147c180] to Queue index [23] Assigning Worker[149] Address:[0x147bfe0] to Queue index [24] Assigning Worker[150] Address:[0x147c100] to Queue index [0] Assigning Worker[151] Address:[0x147be20] to Queue index [1] Assigning Worker[152] Address:[0x147bd80] to Queue index [2] Assigning Worker[153] Address:[0x147be60] to Queue index [3] Assigning Worker[154] Address:[0x147be00] to Queue index [4] Assigning Worker[155] Address:[0x147bdc0] to Queue index [5] Assigning Worker[156] Address:[0x147bd60] to Queue index [6] Assigning Worker[157] Address:[0x147c1a0] to Queue index [7] Assigning Worker[158] Address:[0x147be40] to Queue index [8] Assigning Worker[159] Address:[0x147c120] to Queue index [9] Assigning Worker[160] Address:[0x147bd20] to Queue index [10] Assigning Worker[161] Address:[0x147bda0] to Queue index [11] Assigning Worker[162] Address:[0x147bd40] to Queue index [12] Assigning Worker[163] Address:[0x147bca0] to Queue index [13] Assigning Worker[164] Address:[0x147bcc0] to Queue index [14] Assigning Worker[165] Address:[0x147bde0] to Queue index [15] Assigning Worker[166] Address:[0x147bd00] to Queue index [16] Assigning Worker[167] Address:[0x147bc80] to Queue index [17] Assigning Worker[168] Address:[0x147bc40] to Queue index [18] Assigning Worker[169] Address:[0x147bc60] to Queue index [19] Assigning Worker[170] Address:[0x147bce0] to Queue index [20] Assigning Worker[171] Address:[0x147bb80] to Queue index [21] Assigning Worker[172] Address:[0x147bba0] to Queue index [22] Assigning Worker[173] Address:[0x147bbc0] to Queue index [23] Assigning Worker[174] Address:[0x147bc20] to Queue index [24] Assigning Worker[175] Address:[0x147bc00] to Queue index [0] Assigning Worker[176] Address:[0x147bec0] to Queue index [1] Assigning Worker[177] Address:[0x147bbe0] to Queue index [2] Assigning Worker[178] Address:[0x147be80] to Queue index [3] Assigning Worker[179] Address:[0x147bf40] to Queue index [4] Assigning Worker[180] Address:[0x147bf20] to Queue index [5] Assigning Worker[181] Address:[0x147bf00] to Queue index [6] Assigning Worker[182] Address:[0x147bf60] to Queue index [7] Assigning Worker[183] Address:[0x147bee0] to Queue index [8] Assigning Worker[184] Address:[0x147bb60] to Queue index [9] Assigning Worker[185] Address:[0x147bfa0] to Queue index [10] Assigning Worker[186] Address:[0x147bea0] to Queue index [11] Assigning Worker[187] Address:[0x147bf80] to Queue index [12] Assigning Worker[188] Address:[0x147c0c0] to Queue index [13] Assigning Worker[189] Address:[0x147c020] to Queue index [14] Assigning Worker[190] Address:[0x147c040] to Queue index [15] Assigning Worker[191] Address:[0x147bfc0] to Queue index [16] Assigning Worker[192] Address:[0x147c080] to Queue index [17] Assigning Worker[193] Address:[0x147c060] to Queue index [18] Assigning Worker[194] Address:[0x147c0a0] to Queue index [19] Assigning Worker[195] Address:[0x147c000] to Queue index [20] Assigning Worker[196] Address:[0x147c160] to Queue index [21] Assigning Worker[197] Address:[0x147c180] to Queue index [22] Assigning Worker[198] Address:[0x147c140] to Queue index [23] Assigning Worker[199] Address:[0x147c0e0] to Queue index [24] Work is still incomplete=50 Work is still incomplete=25 All Done!! Wow! That was a lot of work! 16 seconds elapsed