2012-09-05 9 views
9

मैं मल्टीथ्रेडिंग से परिचित हूं और मैंने जावा और ऑब्जेक्टिव-सी में सफलतापूर्वक कई बहुप्रचारित प्रोग्राम विकसित किए हैं। लेकिन मैं एक मुख्य थ्रेड से शामिल होने का उपयोग किए बिना pthreads का उपयोग कर सी में निम्नलिखित को प्राप्त नहीं कर सकता है:प्रबंधक के बिना प्रबंधक/कार्यकर्ता pthreads को सिंक्रनाइज़ करने के लिए कैसे?

मुख्य में():

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 

#define NUM_OF_THREADS 2 

struct thread_data { 
    int start; 
    int end; 
    int *arr; 
}; 

void print(int *ints, int n); 
void *processArray(void *args); 

int main(int argc, const char * argv[]) 
{ 
    int numOfInts = 10; 
    int *ints = malloc(numOfInts * sizeof(int)); 
    for (int i = 0; i < numOfInts; i++) { 
     ints[i] = i; 
    } 
    print(ints, numOfInts); // prints [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

    pthread_t threads[NUM_OF_THREADS]; 
    struct thread_data thread_data[NUM_OF_THREADS]; 

    // these vars are used to calculate the index ranges for each thread 
    int remainingWork = numOfInts, amountOfWork; 
    int startRange, endRange = -1; 

    for (int i = 0; i < NUM_OF_THREADS; i++) { 

     amountOfWork = remainingWork/(NUM_OF_THREADS - i); 
     startRange = endRange + 1; 
     endRange = startRange + amountOfWork - 1; 

     thread_data[i].arr = ints; 
     thread_data[i].start = startRange; 
     thread_data[i].end = endRange; 

     pthread_create(&threads[i], NULL, processArray, (void *)&thread_data[i]); 

     remainingWork -= amountOfWork;  
    } 

    // 1. Signal to the threads to start working 


    // 2. Wait for them to finish 


    print(ints, numOfInts); // should print [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

    free(ints); 
    return 0; 
} 

void *processArray(void *args) 
{ 
    struct thread_data *data = (struct thread_data *)args; 
    int *arr = data->arr; 
    int start = data->start; 
    int end = data->end; 

    // 1. Wait for a signal to start from the main thread 


    for (int i = start; i <= end; i++) { 
     arr[i] = arr[i] + 1; 
    } 

    // 2. Signal to the main thread that you're done 

    pthread_exit(NULL); 
} 

void print(int *ints, int n) 
{ 
    printf("["); 
    for (int i = 0; i < n; i++) { 
     printf("%d", ints[i]); 
     if (i+1 != n) 
      printf(", "); 
    } 
    printf("]\n"); 
} 

मैं उपरोक्त कोड में निम्नलिखित प्राप्त करने के लिए चाहते हैं

  1. काम शुरू करने के लिए धागे पर सिग्नल करें।
  2. पृष्ठभूमि धागे को समाप्त करने के लिए प्रतीक्षा करें।

processArray() में:

एक संकेत के लिए
  1. प्रतीक्षा मुख्य थ्रेड
  2. सिग्नल मुख्य थ्रेड कि आपका काम हो गया करने के लिए से शुरू करने के लिए

मुझे नहीं पता मुख्य धागे में शामिल होने का उपयोग करना चाहते हैं क्योंकि the real application में, मुख्य धागा एक बार थ्रेड बना देगा, और फिर यह पृष्ठभूमि थ्रेड को कई बार काम करने के लिए संकेत देगा, और मैं मुख्य थ्रेड को तब तक आगे नहीं बढ़ सकता जब तक कि सभी पृष्ठभूमि thr ईड्स काम खत्म कर दिया है। processArray समारोह में, मैं निम्नलिखित के रूप में अनंत लूप रखा जाएगा:

void *processArray(void *args) 
{ 
    struct thread_data *data = (struct thread_data *)args; 

    while (1) 
    { 
     // 1. Wait for a signal to start from the main thread 

     int *arr = data->arr; 
     int start = data->start; 
     int end = data->end;   

     // Process 
     for (int i = start; i <= end; i++) { 
      arr[i] = arr[i] + 1; 
     } 

     // 2. Signal to the main thread that you're done 

    } 

    pthread_exit(NULL); 
} 

ध्यान दें कि मैं सी और POSIX एपीआई के लिए नया हूँ, इसलिए मुझे क्षमा करें यदि मैं कुछ स्पष्ट याद कर रहा हूँ। लेकिन मैंने वास्तव में कई चीजों की कोशिश की, एक म्यूटेक्स, और सेफफोर्स की एक सरणी, और दोनों का मिश्रण, लेकिन सफलता के बिना। मुझे लगता है कि एक शर्त चर मदद कर सकता है, लेकिन मुझे समझ में नहीं आया कि इसका उपयोग कैसे किया जा सकता है।

आपके समय के लिए धन्यवाद।

समस्या हल:

बहुत बहुत शुक्रिया आप लोग! मैं अंत में इसे सुरक्षित रूप से काम करने और आपकी युक्तियों का पालन करके शामिल होने के बिना प्राप्त करने में सक्षम था। यद्यपि समाधान कुछ हद तक बदसूरत है, लेकिन यह काम पूरा हो जाता है और प्रदर्शन लाभ इसके लायक है (जैसा कि आप नीचे देखेंगे)। रुचि किसी के लिए, यह असली आवेदन मैं पर काम कर रहा हूँ, जिसमें मुख्य थ्रेड पृष्ठभूमि धागे को लगातार काम दे रही रखता है के अनुकरण है:

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 

#define NUM_OF_THREADS 5 

struct thread_data { 
    int id; 
    int start; 
    int end; 
    int *arr; 
}; 

pthread_mutex_t currentlyIdleMutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t currentlyIdleCond = PTHREAD_COND_INITIALIZER; 
int currentlyIdle; 

pthread_mutex_t workReadyMutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t workReadyCond = PTHREAD_COND_INITIALIZER; 
int workReady; 

pthread_cond_t currentlyWorkingCond = PTHREAD_COND_INITIALIZER; 
pthread_mutex_t currentlyWorkingMutex= PTHREAD_MUTEX_INITIALIZER; 
int currentlyWorking; 

pthread_mutex_t canFinishMutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t canFinishCond = PTHREAD_COND_INITIALIZER; 
int canFinish; 

void print(int *ints, int n); 
void *processArray(void *args); 
int validateResult(int *ints, int num, int start); 

int main(int argc, const char * argv[]) 
{ 
    int numOfInts = 10; 
    int *ints = malloc(numOfInts * sizeof(int)); 
    for (int i = 0; i < numOfInts; i++) { 
     ints[i] = i; 
    } 
// print(ints, numOfInts); 

    pthread_t threads[NUM_OF_THREADS]; 
    struct thread_data thread_data[NUM_OF_THREADS]; 
    workReady = 0; 
    canFinish = 0; 
    currentlyIdle = 0; 
    currentlyWorking = 0; 

    // these vars are used to calculate the index ranges for each thread 
    int remainingWork = numOfInts, amountOfWork; 
    int startRange, endRange = -1; 
    // Create the threads and give each one its data struct. 
    for (int i = 0; i < NUM_OF_THREADS; i++) { 

     amountOfWork = remainingWork/(NUM_OF_THREADS - i); 
     startRange = endRange + 1; 
     endRange = startRange + amountOfWork - 1; 

     thread_data[i].id = i; 
     thread_data[i].arr = ints; 
     thread_data[i].start = startRange; 
     thread_data[i].end = endRange; 

     pthread_create(&threads[i], NULL, processArray, (void *)&thread_data[i]); 
     remainingWork -= amountOfWork; 
    } 

    int loops = 1111111; 
    int expectedStartingValue = ints[0] + loops; // used to validate the results 
    // The elements in ints[] should be incremented by 1 in each loop 
    while (loops-- != 0) { 

     // Make sure all of them are ready 
     pthread_mutex_lock(&currentlyIdleMutex); 
     while (currentlyIdle != NUM_OF_THREADS) { 
      pthread_cond_wait(&currentlyIdleCond, &currentlyIdleMutex); 
     } 
     pthread_mutex_unlock(&currentlyIdleMutex); 

     // All threads are now blocked; it's safe to not lock the mutex. 
     // Prevent them from finishing before authorized. 
     canFinish = 0; 
     // Reset the number of currentlyWorking threads 
     currentlyWorking = NUM_OF_THREADS; 

     // Signal to the threads to start 
     pthread_mutex_lock(&workReadyMutex); 
     workReady = 1; 
     pthread_cond_broadcast(&workReadyCond); 
     pthread_mutex_unlock(&workReadyMutex);  

     // Wait for them to finish 
     pthread_mutex_lock(&currentlyWorkingMutex); 
     while (currentlyWorking != 0) { 
      pthread_cond_wait(&currentlyWorkingCond, &currentlyWorkingMutex); 
     } 
     pthread_mutex_unlock(&currentlyWorkingMutex); 

     // The threads are now waiting for permission to finish 
     // Prevent them from starting again 
     workReady = 0; 
     currentlyIdle = 0; 

     // Allow them to finish 
     pthread_mutex_lock(&canFinishMutex); 
     canFinish = 1; 
     pthread_cond_broadcast(&canFinishCond); 
     pthread_mutex_unlock(&canFinishMutex); 
    } 

// print(ints, numOfInts); 

    if (validateResult(ints, numOfInts, expectedStartingValue)) { 
     printf("Result correct.\n"); 
    } 
    else { 
     printf("Result invalid.\n");  
    } 

    // clean up 
    for (int i = 0; i < NUM_OF_THREADS; i++) { 
     pthread_cancel(threads[i]); 
    } 
    free(ints); 

    return 0; 
} 

void *processArray(void *args) 
{ 
    struct thread_data *data = (struct thread_data *)args; 
    int *arr = data->arr; 
    int start = data->start; 
    int end = data->end; 

    while (1) { 

     // Set yourself as idle and signal to the main thread, when all threads are idle main will start 
     pthread_mutex_lock(&currentlyIdleMutex); 
     currentlyIdle++; 
     pthread_cond_signal(&currentlyIdleCond); 
     pthread_mutex_unlock(&currentlyIdleMutex); 

     // wait for work from main 
     pthread_mutex_lock(&workReadyMutex); 
     while (!workReady) { 
      pthread_cond_wait(&workReadyCond , &workReadyMutex); 
     } 
     pthread_mutex_unlock(&workReadyMutex); 

     // Do the work 
     for (int i = start; i <= end; i++) { 
      arr[i] = arr[i] + 1; 
     } 

     // mark yourself as finished and signal to main 
     pthread_mutex_lock(&currentlyWorkingMutex); 
     currentlyWorking--; 
     pthread_cond_signal(&currentlyWorkingCond); 
     pthread_mutex_unlock(&currentlyWorkingMutex); 

     // Wait for permission to finish 
     pthread_mutex_lock(&canFinishMutex); 
     while (!canFinish) { 
      pthread_cond_wait(&canFinishCond , &canFinishMutex); 
     } 
     pthread_mutex_unlock(&canFinishMutex); 
    } 

    pthread_exit(NULL); 
} 

int validateResult(int *ints, int n, int start) 
{ 
    int tmp = start; 
    for (int i = 0; i < n; i++, tmp++) { 
     if (ints[i] != tmp) { 
      return 0; 
     } 
    } 
    return 1; 
} 

void print(int *ints, int n) 
{ 
    printf("["); 
    for (int i = 0; i < n; i++) { 
     printf("%d", ints[i]); 
     if (i+1 != n) 
      printf(", "); 
    } 
    printf("]\n"); 
} 

मुझे यकीन है कि हालांकि अगर pthread_cancel के लिए पर्याप्त है नहीं कर रहा हूँ साफ - सफाई! बाधा के लिए, अगर यह @Jeremy द्वारा उल्लिखित कुछ ओएस तक ही सीमित नहीं था, तो यह बहुत मददगार होगा।

मानक:

मुझे यकीन है कि इनमें से कई की स्थिति वास्तव में एल्गोरिथ्म धीमा नहीं कर रहे हैं बनाना चाहते थे, इसलिए मैं सेटअप इस बेंचमार्क है दो समाधान तुलना करने के लिए:

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
#include <unistd.h> 
#include <sys/time.h> 
#include <sys/resource.h> 

#define NUM_OF_THREADS 5 
struct thread_data { 
    int start; 
    int end; 
    int *arr; 
}; 
pthread_mutex_t currentlyIdleMutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t currentlyIdleCond = PTHREAD_COND_INITIALIZER; 
int currentlyIdle; 
pthread_mutex_t workReadyMutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t workReadyCond = PTHREAD_COND_INITIALIZER; 
int workReady; 
pthread_cond_t currentlyWorkingCond = PTHREAD_COND_INITIALIZER; 
pthread_mutex_t currentlyWorkingMutex= PTHREAD_MUTEX_INITIALIZER; 
int currentlyWorking; 
pthread_mutex_t canFinishMutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t canFinishCond = PTHREAD_COND_INITIALIZER; 
int canFinish; 

void *processArrayMutex(void *args); 
void *processArrayJoin(void *args); 
double doItWithMutex(pthread_t *threads, struct thread_data *data, int loops); 
double doItWithJoin(pthread_t *threads, struct thread_data *data, int loops); 

int main(int argc, const char * argv[]) 
{ 
    int numOfInts = 10; 
    int *join_ints = malloc(numOfInts * sizeof(int)); 
    int *mutex_ints = malloc(numOfInts * sizeof(int)); 
    for (int i = 0; i < numOfInts; i++) { 
     join_ints[i] = i; 
     mutex_ints[i] = i; 
    } 

    pthread_t join_threads[NUM_OF_THREADS]; 
    pthread_t mutex_threads[NUM_OF_THREADS]; 
    struct thread_data join_thread_data[NUM_OF_THREADS]; 
    struct thread_data mutex_thread_data[NUM_OF_THREADS]; 
    workReady = 0; 
    canFinish = 0; 
    currentlyIdle = 0; 
    currentlyWorking = 0; 

    int remainingWork = numOfInts, amountOfWork; 
    int startRange, endRange = -1; 
    for (int i = 0; i < NUM_OF_THREADS; i++) { 
     amountOfWork = remainingWork/(NUM_OF_THREADS - i); 
     startRange = endRange + 1; 
     endRange = startRange + amountOfWork - 1; 

     join_thread_data[i].arr = join_ints; 
     join_thread_data[i].start = startRange; 
     join_thread_data[i].end = endRange; 
     mutex_thread_data[i].arr = mutex_ints; 
     mutex_thread_data[i].start = startRange; 
     mutex_thread_data[i].end = endRange; 

     pthread_create(&mutex_threads[i], NULL, processArrayMutex, (void *)&mutex_thread_data[i]); 
     remainingWork -= amountOfWork; 
    } 

    int numOfBenchmarkTests = 100; 
    int numberOfLoopsPerTest= 1000; 

    double join_sum = 0.0, mutex_sum = 0.0; 
    for (int i = 0; i < numOfBenchmarkTests; i++) 
    { 
     double joinTime = doItWithJoin(join_threads, join_thread_data, numberOfLoopsPerTest); 
     double mutexTime= doItWithMutex(mutex_threads, mutex_thread_data, numberOfLoopsPerTest); 

     join_sum += joinTime; 
     mutex_sum+= mutexTime;  
    } 

    double join_avg = join_sum/numOfBenchmarkTests; 
    double mutex_avg= mutex_sum/numOfBenchmarkTests; 

    printf("Join average : %f\n", join_avg); 
    printf("Mutex average: %f\n", mutex_avg); 

    double diff = join_avg - mutex_avg; 
    if (diff > 0.0) 
     printf("Mutex is %.0f%% faster.\n", 100 * diff/join_avg); 
    else if (diff < 0.0) 
     printf("Join is %.0f%% faster.\n", 100 * diff/mutex_avg); 
    else 
     printf("Both have the same performance."); 

    free(join_ints); 
    free(mutex_ints); 

    return 0; 
} 

// From https://stackoverflow.com/a/2349941/408286 
double get_time() 
{ 
    struct timeval t; 
    struct timezone tzp; 
    gettimeofday(&t, &tzp); 
    return t.tv_sec + t.tv_usec*1e-6; 
} 

double doItWithMutex(pthread_t *threads, struct thread_data *data, int num_loops) 
{ 
    double start = get_time(); 

    int loops = num_loops; 
    while (loops-- != 0) { 
     // Make sure all of them are ready 
     pthread_mutex_lock(&currentlyIdleMutex); 
     while (currentlyIdle != NUM_OF_THREADS) { 
      pthread_cond_wait(&currentlyIdleCond, &currentlyIdleMutex); 
     } 
     pthread_mutex_unlock(&currentlyIdleMutex); 

     // All threads are now blocked; it's safe to not lock the mutex. 
     // Prevent them from finishing before authorized. 
     canFinish = 0; 
     // Reset the number of currentlyWorking threads 
     currentlyWorking = NUM_OF_THREADS; 

     // Signal to the threads to start 
     pthread_mutex_lock(&workReadyMutex); 
     workReady = 1; 
     pthread_cond_broadcast(&workReadyCond); 
     pthread_mutex_unlock(&workReadyMutex); 

     // Wait for them to finish 
     pthread_mutex_lock(&currentlyWorkingMutex); 
     while (currentlyWorking != 0) { 
      pthread_cond_wait(&currentlyWorkingCond, &currentlyWorkingMutex); 
     } 
     pthread_mutex_unlock(&currentlyWorkingMutex); 

     // The threads are now waiting for permission to finish 
     // Prevent them from starting again 
     workReady = 0; 
     currentlyIdle = 0; 

     // Allow them to finish 
     pthread_mutex_lock(&canFinishMutex); 
     canFinish = 1; 
     pthread_cond_broadcast(&canFinishCond); 
     pthread_mutex_unlock(&canFinishMutex); 
    } 

    return get_time() - start; 
} 

double doItWithJoin(pthread_t *threads, struct thread_data *data, int num_loops) 
{ 
    double start = get_time(); 

    int loops = num_loops; 
    while (loops-- != 0) { 
     // create them 
     for (int i = 0; i < NUM_OF_THREADS; i++) { 
      pthread_create(&threads[i], NULL, processArrayJoin, (void *)&data[i]); 
     } 
     // wait 
     for (int i = 0; i < NUM_OF_THREADS; i++) { 
      pthread_join(threads[i], NULL); 
     } 
    } 

    return get_time() - start; 
} 

void *processArrayMutex(void *args) 
{ 
    struct thread_data *data = (struct thread_data *)args; 
    int *arr = data->arr; 
    int start = data->start; 
    int end = data->end; 

    while (1) { 

     // Set yourself as idle and signal to the main thread, when all threads are idle main will start 
     pthread_mutex_lock(&currentlyIdleMutex); 
     currentlyIdle++; 
     pthread_cond_signal(&currentlyIdleCond); 
     pthread_mutex_unlock(&currentlyIdleMutex); 

     // wait for work from main 
     pthread_mutex_lock(&workReadyMutex); 
     while (!workReady) { 
      pthread_cond_wait(&workReadyCond , &workReadyMutex); 
     } 
     pthread_mutex_unlock(&workReadyMutex); 

     // Do the work 
     for (int i = start; i <= end; i++) { 
      arr[i] = arr[i] + 1; 
     } 

     // mark yourself as finished and signal to main 
     pthread_mutex_lock(&currentlyWorkingMutex); 
     currentlyWorking--; 
     pthread_cond_signal(&currentlyWorkingCond); 
     pthread_mutex_unlock(&currentlyWorkingMutex); 

     // Wait for permission to finish 
     pthread_mutex_lock(&canFinishMutex); 
     while (!canFinish) { 
      pthread_cond_wait(&canFinishCond , &canFinishMutex); 
     } 
     pthread_mutex_unlock(&canFinishMutex); 
    } 

    pthread_exit(NULL); 
} 

void *processArrayJoin(void *args) 
{ 
    struct thread_data *data = (struct thread_data *)args; 
    int *arr = data->arr; 
    int start = data->start; 
    int end = data->end; 

    // Do the work 
    for (int i = start; i <= end; i++) { 
     arr[i] = arr[i] + 1; 
    } 

    pthread_exit(NULL); 
} 

और आउटपुट है:

Join average : 0.153074 
Mutex average: 0.071588 
Mutex is 53% faster. 

फिर से धन्यवाद।तुम्हारी मदद के लिए शुक्रिया!

+0

क्षमा करें, आपके प्रश्न को ध्यान से नहीं पढ़ा। आपको क्रमांकित 2 टिप्पणी पर पुन: प्रवेश बाधा लागू करने की आवश्यकता है। Http://pcbec3.ihep.su/~miagkov/code/barrier.c – nhahtdh

+0

@nhahtdh इसके बारे में चिंता न करें। मैं कोड पर एक नज़र डालेगा। धन्यवाद! – Motasim

+0

माइकल बोर ने ऐसा करने के लिए एक मौजूदा कार्य का सुझाव दिया। (मैंने सोचा था कि पोसिक्स ने इसे परिभाषित नहीं किया है, लेकिन यह सब वहाँ है)। – nhahtdh

उत्तर

2

आपको join की तुलना में एक अलग सिंक्रनाइज़ेशन तकनीक का उपयोग करने की आवश्यकता है, यह स्पष्ट है।

दुर्भाग्य से आपके पास बहुत सारे विकल्प हैं। एक "सिंक्रनाइज़ेशन बाधा" है, जो मूल रूप से एक चीज है जहां प्रत्येक धागा जो तब तक पहुंचता है जब तक कि वे सभी तक पहुंच नहीं जाते हैं (आप अग्रिम में थ्रेड की संख्या निर्दिष्ट करते हैं)। pthread_barrier पर देखें।

दूसरा एक शर्त-परिवर्तनीय/म्यूटेक्स जोड़ी (pthread_cond_*) का उपयोग करना है। जब प्रत्येक धागा खत्म होता है तो यह म्यूटेक्स लेता है, एक गिनती बढ़ाता है, कन्वेयर को संकेत देता है। मुख्य धागा कंडवार पर इंतजार करता है जब तक कि गिनती उस मूल्य तक पहुंच जाती है जब तक वह अपेक्षा करता है। कोड इस तरह दिखता है:

// thread has finished 
mutex_lock 
++global_count 
// optional optimization: only execute the next line when global_count >= N 
cond_signal 
mutex_unlock 

// main is waiting for N threads to finish 
mutex_lock 
while (global_count < N) { 
    cond_wait 
} 
mutex_unlock 

एक और धागा प्रति एक सेमाफोर उपयोग करने के लिए है - जब धागा खत्म यह अपने आप ही सेमाफोर पोस्ट, और बदले में प्रत्येक सेमाफोर पर मुख्य थ्रेड प्रतीक्षा करता है बजाय बदले में प्रत्येक थ्रेड में शामिल होने ।

आपको अगली नौकरी के लिए धागे को दोबारा शुरू करने के लिए सिंक्रनाइज़ेशन की भी आवश्यकता है - यह पहले की तरह एक ही प्रकार का दूसरा सिंक्रनाइज़ेशन ऑब्जेक्ट हो सकता है, इस तथ्य के लिए विवरण बदल गया है कि आपके पास 1 पोस्टर और एन वेटर हैं दूसरी तरफ से। या आप (देखभाल के साथ) दोनों उद्देश्यों के लिए एक ही वस्तु का फिर से उपयोग कर सकते हैं।

यदि आपने इन चीजों को आजमाया है और आपका कोड काम नहीं करता है, तो शायद आपके द्वारा किए गए कोड के बारे में एक नया विशिष्ट प्रश्न पूछें। वे सभी कार्य के लिए पर्याप्त हैं।

+0

धन्यवाद स्टीव! आपकी युक्तियाँ सबसे मूल्यवान थीं :) – Motasim

1

काम करने के लिए सभी धागे को बताने के लिए, यह एक वैश्विक पूर्णांक चर के रूप में सरल हो सकता है जिसे शून्य में प्रारंभ किया गया है, और थ्रेड बस शून्य होने तक प्रतीक्षा करते हैं। इस तरह आपको थ्रेड फ़ंक्शन में while (1) लूप की आवश्यकता नहीं है।

जब तक वे सब कुछ नहीं किया जाता है, तब तक प्रतीक्षा करने के लिए, pthread_join सबसे सरल है क्योंकि यह वास्तव में तब तक अवरुद्ध हो जाएगा जब तक यह शामिल हो रहा है। धागे के बाद सिस्टम सामान को साफ करने की भी आवश्यकता है (अन्यथा धागे से वापसी मूल्य प्रोग्राम के शेष भाग के लिए संग्रहीत किया जाएगा)। चूंकि आपके पास धागे के लिए सभी pthread_t की सरणी है, तो बस उन पर एक-एक करके लूप करें। चूंकि आपके प्रोग्राम का वह हिस्सा कुछ और नहीं करता है, और जब तक सभी धागे नहीं किए जाते हैं, तब तक इंतजार करना पड़ता है, बस उनके लिए प्रतीक्षा करना ठीक है।

+0

धन्यवाद जोआचिम, माइकल के लिए एक ही सवाल: क्या मुख्य धागा पृष्ठभूमि थ्रेड में शामिल हो सकता है भले ही पृष्ठभूमि थ्रेड वापस नहीं आया या 'pthread_exit' को कॉल करें? क्योंकि जैसा कि मैंने लिखा था, पृष्ठभूमि धागे अनंत लूप में होंगे। – Motasim

+0

@Mota जबकि कार्यक्रम चल रहा है, जबकि थ्रेड लूपिंग हो सकता है, उन्हें कुछ समय रोकना होगा। या तो आप उन्हें रोकने के लिए कह रहे हैं (सरल पूर्णांक चर का उपयोग करके यहां भी पर्याप्त है) या मुख्य धागे से बाहर निकलने से (यानी 'मुख्य' से लौटकर या 'निकास' को कॉल करना)। 'Pthread_join' फ़ंक्शन _will_ ब्लॉक जब तक यह बाहर निकलने वाले थ्रेड तक नहीं हो जाता है। –

+0

धन्यवाद जोआचिम! आपकी युक्तियाँ बहुत मूल्यवान थीं। – Motasim

4

कई सिंक्रनाइज़ेशन तंत्र हैं जिनका आप उपयोग कर सकते हैं (उदाहरण के लिए स्थिति चर)। मुझे लगता है कि थ्रेड की शुरुआत सिंक्रनाइज़ करने के लिए pthread_barrier का उपयोग करना सबसे आसान होगा।

यह मानते हुए कि आप सभी थ्रेड को प्रत्येक लूप पुनरावृत्ति पर 'सिंक अप' करना चाहते हैं, तो आप केवल बाधा का पुन: उपयोग कर सकते हैं। यदि आपको कुछ और लचीला चाहिए, तो एक शर्त चर अधिक उपयुक्त हो सकता है।

जब आप तय करते हैं कि थ्रेड को लपेटने के लिए समय है (आपने संकेत नहीं दिया है कि थ्रेड को अनंत लूप से कैसे तोड़ने के बारे में पता चल जाएगा - इसके लिए एक साझा साझा चर का उपयोग किया जा सकता है; साझा चर एक हो सकता है परमाणु प्रकार या एक म्यूटेक्स के साथ संरक्षित), main() धागे को सभी धागे को पूरा करने के लिए pthread_join() का उपयोग करना चाहिए।

+0

धन्यवाद माइकल, लेकिन क्या मुख्य धागा पृष्ठभूमि थ्रेड में शामिल हो सकता है भले ही पृष्ठभूमि थ्रेड वापस नहीं आया या 'pthread_exit' को कॉल करें? क्योंकि जैसा कि मैंने लिखा था, पृष्ठभूमि धागे अनंत लूप में होंगे। – Motasim

+0

@ मोटा: क्षमा करें - मुझे इस सवाल का हिस्सा याद आया। मैंने जवाब अपडेट कर लिया है। यदि आपकी ज़रूरतें सरल हैं, तो बाधा का पुन: उपयोग किया जा सकता है; यदि आपकी ज़रूरतें अधिक जटिल हैं तो आप 'pthread_cond_t' स्थिति चर का उपयोग करना चाहेंगे (आपको एक से अधिक की आवश्यकता हो सकती है)। –

+0

सिद्धांत रूप में आपको * एक से अधिक कंडीशन वैरिएबल की आवश्यकता नहीं होगी, क्योंकि अलग-अलग लोग एक ही म्यूटेक्स/कोंडवर जोड़ी का उपयोग करके विभिन्न स्थितियों पर अलग-अलग स्थितियों का परीक्षण कर सकते हैं, और जब भी कोई भी स्थिति बदलती है तो आप कंडवर प्रसारित करते हैं। दक्षता और कोड स्पष्टता के लिए आप * एक से अधिक * चाहते हैं। –

1

आप अमूर्तता के गलत स्तर पर काम कर रहे हैं। यह समस्या पहले ही हल हो चुकी है। आप एक कार्य कतार + थ्रेड पूल को फिर से कार्यान्वित कर रहे हैं।

OpenMP आपकी समस्या के लिए एक अच्छा फिट लगता है। यह #pragma एनोटेशन को थ्रेडेड कोड में परिवर्तित करता है। मेरा मानना ​​है कि यह आपको स्पष्ट रूप से करने की कोशिश कर रहा है कि आप क्या व्यक्त कर रहे हैं।

libdispatch का उपयोग करके, आप जो करने का प्रयास कर रहे हैं उसे एक समवर्ती कतार को लक्षित करने वाले dispatch_apply के रूप में व्यक्त किया जाएगा। यह पूरी तरह से सभी बाल कार्यों को पूरा करने के लिए इंतजार कर रहा है। ओएस एक्स के तहत, यह एक गैर पोर्टेबल पठ्रेड वर्क्यूयू इंटरफ़ेस का उपयोग करके लागू किया गया है; फ्रीबीएसडी के तहत, मुझे विश्वास है कि यह सीधे pthreads के एक समूह का प्रबंधन करता है।

यदि पोर्टेबिलिटी आपको कच्चे pthreads का उपयोग करने के लिए ड्राइविंग करने वाली चिंताओं है, तो pthread बाधाओं का उपयोग न करें। बाधाएं मूल POSIX धागे से ऊपर और ऊपर एक अतिरिक्त एक्सटेंशन हैं। उदाहरण के लिए ओएस एक्स इसका समर्थन नहीं करता है। अधिक के लिए, POSIX देखें।

मुख्य धागे को अवरुद्ध करने तक मुख्य धागे को अवरुद्ध कर दिया गया है, एक शर्त चर द्वारा संरक्षित गिनती का उपयोग करके या यहां तक ​​कि अधिक आसानी से, एक पाइप और अवरुद्ध पढ़ने का उपयोग करके जहां बाइट्स की संख्या पढ़ने के लिए धागे की संख्या से मेल खाती है । प्रत्येक धागा कार्य पूरा करने पर एक बाइट लिखता है, तब तक सो जाता है जब तक कि यह मुख्य धागे से नया काम न हो जाए। एक बार प्रत्येक धागे ने लिखा है "मैं कर चुका हूँ!" मुख्य थ्रेड unblocks बाइट।

बाल धागे को काम पास करना एक म्यूटेक्स का उपयोग करके कार्य-वर्णनकर्ता की रक्षा और नए काम को सिग्नल करने की शर्त का उपयोग करके किया जा सकता है। आप कार्य डिस्क्रिप्टरों की एक एकल सरणी का उपयोग कर सकते हैं कि सभी धागे से आकर्षित होते हैं। सिग्नल पर, प्रत्येक म्यूटेक्स को पकड़ने की कोशिश करता है। म्यूटेक्स को पकड़ने पर, यह कुछ काम को अस्वीकार कर देगा, अगर कतार अपरिवर्तनीय है, तो उसके सिग्नल को फिर से चालू करें, और फिर उसके काम को संसाधित करें, जिसके बाद यह मास्टर थ्रेड को पूरा करने का संकेत देगा।

परिणाम के अनुसार मुख्य थ्रेड को अनदेखा करने के लिए आप इस "कार्य कतार" का पुन: उपयोग कर सकते हैं, परिणामस्वरूप कतार लंबाई तक धागे की संख्या से मेल खाता है; पाइप दृष्टिकोण सिर्फ आपके लिए यह गिनती करने के लिए अवरुद्ध read का उपयोग कर रहा है।

+0

धन्यवाद जेरेमी! आपकी युक्तियाँ बहुत मूल्यवान थीं! – Motasim