In answering password cracker in c with multithreading, I ended up writing a sample in C, which is not my forte.
Is there anything that I missed which should have been included in a responsible sample (read: likely to be copied and pasted into production code)?
// compile with `gcc counter.c -o counter -lpthread -Wall -std=gnu99`
#include <pthread.h>
#include <stdio.h>
#include <stdbool.h>
#include <limits.h>
#define SEARCH_THREAD_COUNT (10)
#define SEARCH_VALUE (21325)
#define SEARCH_MAX (INT_MAX)
typedef struct {
int start;
int end;
int search;
bool* shouldStop;
int* answer;
pthread_mutex_t* answerMutex;
pthread_cond_t* answerFound;
pthread_t thisThread;
} find_worker_init;
void* find_value(void* vpInitInfo) {
find_worker_init* pUnitOfWork = (find_worker_init*)vpInitInfo;
int cValue = pUnitOfWork->start;
while (!(*(pUnitOfWork->shouldStop))) {
if (cValue == pUnitOfWork->search) {
printf("found value\n");
// found the search value
pthread_mutex_lock(pUnitOfWork->answerMutex);
if (!(*(pUnitOfWork->shouldStop))) {
*(pUnitOfWork->shouldStop) = true;
*(pUnitOfWork->answer) = cValue;
pthread_cond_broadcast(pUnitOfWork->answerFound);
}
pthread_mutex_unlock(pUnitOfWork->answerMutex);
return NULL;
}
cValue++;
if (cValue == pUnitOfWork->end) {
// we exhausted our search space, end.
printf("exhausted\n");
return NULL;
}
}
// we were usurped by another thread
printf("usurped\n");
return NULL;
}
int main( int argc, const char* argv[] ) {
pthread_mutex_t answerMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t answerFound = PTHREAD_COND_INITIALIZER;
bool shouldStop = false;
int answer = -1;
// initialize thread jobs
find_worker_init startInfo[SEARCH_THREAD_COUNT];
int current_search_start = 0;
int search_unit = SEARCH_MAX / SEARCH_THREAD_COUNT;
for (int i = 0; i < SEARCH_THREAD_COUNT; i++) {
startInfo[i].start = current_search_start;
// set the search space for this thread to be either the standard
// search space, or for the last thread, whatever is remaining
// (this is to prevent integer-division from skipping a portion
// at the end)
int current_size = (i == SEARCH_THREAD_COUNT - 1)
? (SEARCH_MAX - current_search_start)
: search_unit;
startInfo[i].end = current_search_start + current_size;
startInfo[i].search = SEARCH_VALUE;
startInfo[i].shouldStop = &shouldStop;
startInfo[i].answer = &answer;
startInfo[i].answerMutex = &answerMutex;
startInfo[i].answerFound = &answerFound;
}
// start threads
for (int i = 0; i < SEARCH_THREAD_COUNT; i++) {
if (pthread_create(&(startInfo[i].thisThread), NULL, find_value,
&(startInfo[i])))
{
fprintf(stderr, "Error creating thread\n");
return 1;
}
}
// wait for answer to be found
pthread_mutex_lock(&answerMutex);
while (!shouldStop) {
pthread_cond_wait(&answerFound, &answerMutex);
}
printf("signaled\n");
// join
for (int i = 0; i < SEARCH_THREAD_COUNT; i++) {
if (pthread_join(startInfo[i].thisThread, NULL)) {
fprintf(stderr, "Error joining thread\n");
return 1;
}
}
// answer
printf("answer: %d\n", answer);
pthread_mutex_unlock(&answerMutex);
return 0;
}
int answer = SEARCH_VALUE; print answer;
\$\endgroup\$current_search_start
is not updated. Problem? \$\endgroup\$