C: Maintaining N simultaneous pthreads at a time for M>>N independent calculations











up vote
0
down vote

favorite












I have a problem that requires me to execute a particular calculation of variable length a large number of times (typically > 10^8) and I have a small number of processors (<=16) to run it on. The simplified code below successfully creates pthreads in batches of NTHREADS at a time, but it has the deficiency that everything else pauses until the slowest thread in each batch completes. Since the slowest thread can occasionally be 10-100 times slower than the fastest thread, this means processors may be idle for a large fraction of the time, on average.



What I would like to do is keep all processors busy by creating a new pthread each time one terminates. I could easily do this if there were a way to retrieve the current number of active pthreads, but I haven't found a way to do that.



Is this possible? If so, how?



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

struct arg_struct {
double x ;
double y ;
};

int nloops = 0 ; // initialize loop counter

void process(struct arg_struct *args)
{
int thisloop ;

float x,y ;
x = args->x ; y = args->y ;
free(args) ; // we're done with passed arguments

nloops++ ; // increment global counter
thisloop = nloops ; // capture current loop number

sleep(11-nloops) ; // variable delay
printf("thisloop = %d threadID = %d args = %.1f %.1fn", thisloop, (int) pthread_self(), x, y) ;

pthread_exit(NULL); // exit thread
}

int main()
{
const int MINLOOPS = 10 ; // total number of loops to execute
const int MAXTHREADS = 4 ; // maximum number of threads at any one time

int N, remaining ;
pthread_t tid[MAXTHREADS];

while (1)
{
remaining = MINLOOPS - nloops ;
if (remaining == 0) break ;
if (remaining < MAXTHREADS)
N = remaining;
else
N = MAXTHREADS;

for (int i = 0; i < N; i++) { // create a set of simultaneous threads

struct arg_struct *args = malloc(sizeof(struct arg_struct)); // initialize arguments
args->x = i; args->y = -i ;

pthread_create(&tid[i], NULL, (void *) process, (void *) args ) ;
printf("Created thread %dn", (int) tid[i]) ;
}

for (int i = 0; i < N; i++) // wait until all threads in current loop have completed
pthread_join(tid[i], NULL);
}
}


Output is:



Created thread 216977408
Created thread 217513984
Created thread 218050560
Created thread 218587136
thisloop = 4 threadID = 218587136 args = 3.0 -3.0
thisloop = 3 threadID = 218050560 args = 2.0 -2.0
thisloop = 2 threadID = 217513984 args = 1.0 -1.0
thisloop = 1 threadID = 216977408 args = 0.0 0.0
Created thread 216977408
Created thread 217513984
Created thread 218050560
Created thread 218587136
thisloop = 8 threadID = 218050560 args = 2.0 -2.0
thisloop = 7 threadID = 218587136 args = 3.0 -3.0
thisloop = 6 threadID = 217513984 args = 1.0 -1.0
thisloop = 5 threadID = 216977408 args = 0.0 0.0
Created thread 216977408
Created thread 217513984
thisloop = 10 threadID = 217513984 args = 1.0 -1.0
thisloop = 9 threadID = 216977408 args = 0.0 0.0









share|improve this question


















  • 2




    You are describing a thread pool. Usually, instead of creating and destroying threads, you will create them all at once and then use some sort of queue to distribute work amongst them. Some technologies will do this for you at compile-time (e.g. OpenMP).
    – paddy
    Nov 5 at 2:31










  • See my proposed solution below.
    – Grant Petty
    Nov 5 at 3:32















up vote
0
down vote

favorite












I have a problem that requires me to execute a particular calculation of variable length a large number of times (typically > 10^8) and I have a small number of processors (<=16) to run it on. The simplified code below successfully creates pthreads in batches of NTHREADS at a time, but it has the deficiency that everything else pauses until the slowest thread in each batch completes. Since the slowest thread can occasionally be 10-100 times slower than the fastest thread, this means processors may be idle for a large fraction of the time, on average.



What I would like to do is keep all processors busy by creating a new pthread each time one terminates. I could easily do this if there were a way to retrieve the current number of active pthreads, but I haven't found a way to do that.



Is this possible? If so, how?



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

struct arg_struct {
double x ;
double y ;
};

int nloops = 0 ; // initialize loop counter

void process(struct arg_struct *args)
{
int thisloop ;

float x,y ;
x = args->x ; y = args->y ;
free(args) ; // we're done with passed arguments

nloops++ ; // increment global counter
thisloop = nloops ; // capture current loop number

sleep(11-nloops) ; // variable delay
printf("thisloop = %d threadID = %d args = %.1f %.1fn", thisloop, (int) pthread_self(), x, y) ;

pthread_exit(NULL); // exit thread
}

int main()
{
const int MINLOOPS = 10 ; // total number of loops to execute
const int MAXTHREADS = 4 ; // maximum number of threads at any one time

int N, remaining ;
pthread_t tid[MAXTHREADS];

while (1)
{
remaining = MINLOOPS - nloops ;
if (remaining == 0) break ;
if (remaining < MAXTHREADS)
N = remaining;
else
N = MAXTHREADS;

for (int i = 0; i < N; i++) { // create a set of simultaneous threads

struct arg_struct *args = malloc(sizeof(struct arg_struct)); // initialize arguments
args->x = i; args->y = -i ;

pthread_create(&tid[i], NULL, (void *) process, (void *) args ) ;
printf("Created thread %dn", (int) tid[i]) ;
}

for (int i = 0; i < N; i++) // wait until all threads in current loop have completed
pthread_join(tid[i], NULL);
}
}


Output is:



Created thread 216977408
Created thread 217513984
Created thread 218050560
Created thread 218587136
thisloop = 4 threadID = 218587136 args = 3.0 -3.0
thisloop = 3 threadID = 218050560 args = 2.0 -2.0
thisloop = 2 threadID = 217513984 args = 1.0 -1.0
thisloop = 1 threadID = 216977408 args = 0.0 0.0
Created thread 216977408
Created thread 217513984
Created thread 218050560
Created thread 218587136
thisloop = 8 threadID = 218050560 args = 2.0 -2.0
thisloop = 7 threadID = 218587136 args = 3.0 -3.0
thisloop = 6 threadID = 217513984 args = 1.0 -1.0
thisloop = 5 threadID = 216977408 args = 0.0 0.0
Created thread 216977408
Created thread 217513984
thisloop = 10 threadID = 217513984 args = 1.0 -1.0
thisloop = 9 threadID = 216977408 args = 0.0 0.0









share|improve this question


















  • 2




    You are describing a thread pool. Usually, instead of creating and destroying threads, you will create them all at once and then use some sort of queue to distribute work amongst them. Some technologies will do this for you at compile-time (e.g. OpenMP).
    – paddy
    Nov 5 at 2:31










  • See my proposed solution below.
    – Grant Petty
    Nov 5 at 3:32













up vote
0
down vote

favorite









up vote
0
down vote

favorite











I have a problem that requires me to execute a particular calculation of variable length a large number of times (typically > 10^8) and I have a small number of processors (<=16) to run it on. The simplified code below successfully creates pthreads in batches of NTHREADS at a time, but it has the deficiency that everything else pauses until the slowest thread in each batch completes. Since the slowest thread can occasionally be 10-100 times slower than the fastest thread, this means processors may be idle for a large fraction of the time, on average.



What I would like to do is keep all processors busy by creating a new pthread each time one terminates. I could easily do this if there were a way to retrieve the current number of active pthreads, but I haven't found a way to do that.



Is this possible? If so, how?



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

struct arg_struct {
double x ;
double y ;
};

int nloops = 0 ; // initialize loop counter

void process(struct arg_struct *args)
{
int thisloop ;

float x,y ;
x = args->x ; y = args->y ;
free(args) ; // we're done with passed arguments

nloops++ ; // increment global counter
thisloop = nloops ; // capture current loop number

sleep(11-nloops) ; // variable delay
printf("thisloop = %d threadID = %d args = %.1f %.1fn", thisloop, (int) pthread_self(), x, y) ;

pthread_exit(NULL); // exit thread
}

int main()
{
const int MINLOOPS = 10 ; // total number of loops to execute
const int MAXTHREADS = 4 ; // maximum number of threads at any one time

int N, remaining ;
pthread_t tid[MAXTHREADS];

while (1)
{
remaining = MINLOOPS - nloops ;
if (remaining == 0) break ;
if (remaining < MAXTHREADS)
N = remaining;
else
N = MAXTHREADS;

for (int i = 0; i < N; i++) { // create a set of simultaneous threads

struct arg_struct *args = malloc(sizeof(struct arg_struct)); // initialize arguments
args->x = i; args->y = -i ;

pthread_create(&tid[i], NULL, (void *) process, (void *) args ) ;
printf("Created thread %dn", (int) tid[i]) ;
}

for (int i = 0; i < N; i++) // wait until all threads in current loop have completed
pthread_join(tid[i], NULL);
}
}


Output is:



Created thread 216977408
Created thread 217513984
Created thread 218050560
Created thread 218587136
thisloop = 4 threadID = 218587136 args = 3.0 -3.0
thisloop = 3 threadID = 218050560 args = 2.0 -2.0
thisloop = 2 threadID = 217513984 args = 1.0 -1.0
thisloop = 1 threadID = 216977408 args = 0.0 0.0
Created thread 216977408
Created thread 217513984
Created thread 218050560
Created thread 218587136
thisloop = 8 threadID = 218050560 args = 2.0 -2.0
thisloop = 7 threadID = 218587136 args = 3.0 -3.0
thisloop = 6 threadID = 217513984 args = 1.0 -1.0
thisloop = 5 threadID = 216977408 args = 0.0 0.0
Created thread 216977408
Created thread 217513984
thisloop = 10 threadID = 217513984 args = 1.0 -1.0
thisloop = 9 threadID = 216977408 args = 0.0 0.0









share|improve this question













I have a problem that requires me to execute a particular calculation of variable length a large number of times (typically > 10^8) and I have a small number of processors (<=16) to run it on. The simplified code below successfully creates pthreads in batches of NTHREADS at a time, but it has the deficiency that everything else pauses until the slowest thread in each batch completes. Since the slowest thread can occasionally be 10-100 times slower than the fastest thread, this means processors may be idle for a large fraction of the time, on average.



What I would like to do is keep all processors busy by creating a new pthread each time one terminates. I could easily do this if there were a way to retrieve the current number of active pthreads, but I haven't found a way to do that.



Is this possible? If so, how?



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

struct arg_struct {
double x ;
double y ;
};

int nloops = 0 ; // initialize loop counter

void process(struct arg_struct *args)
{
int thisloop ;

float x,y ;
x = args->x ; y = args->y ;
free(args) ; // we're done with passed arguments

nloops++ ; // increment global counter
thisloop = nloops ; // capture current loop number

sleep(11-nloops) ; // variable delay
printf("thisloop = %d threadID = %d args = %.1f %.1fn", thisloop, (int) pthread_self(), x, y) ;

pthread_exit(NULL); // exit thread
}

int main()
{
const int MINLOOPS = 10 ; // total number of loops to execute
const int MAXTHREADS = 4 ; // maximum number of threads at any one time

int N, remaining ;
pthread_t tid[MAXTHREADS];

while (1)
{
remaining = MINLOOPS - nloops ;
if (remaining == 0) break ;
if (remaining < MAXTHREADS)
N = remaining;
else
N = MAXTHREADS;

for (int i = 0; i < N; i++) { // create a set of simultaneous threads

struct arg_struct *args = malloc(sizeof(struct arg_struct)); // initialize arguments
args->x = i; args->y = -i ;

pthread_create(&tid[i], NULL, (void *) process, (void *) args ) ;
printf("Created thread %dn", (int) tid[i]) ;
}

for (int i = 0; i < N; i++) // wait until all threads in current loop have completed
pthread_join(tid[i], NULL);
}
}


Output is:



Created thread 216977408
Created thread 217513984
Created thread 218050560
Created thread 218587136
thisloop = 4 threadID = 218587136 args = 3.0 -3.0
thisloop = 3 threadID = 218050560 args = 2.0 -2.0
thisloop = 2 threadID = 217513984 args = 1.0 -1.0
thisloop = 1 threadID = 216977408 args = 0.0 0.0
Created thread 216977408
Created thread 217513984
Created thread 218050560
Created thread 218587136
thisloop = 8 threadID = 218050560 args = 2.0 -2.0
thisloop = 7 threadID = 218587136 args = 3.0 -3.0
thisloop = 6 threadID = 217513984 args = 1.0 -1.0
thisloop = 5 threadID = 216977408 args = 0.0 0.0
Created thread 216977408
Created thread 217513984
thisloop = 10 threadID = 217513984 args = 1.0 -1.0
thisloop = 9 threadID = 216977408 args = 0.0 0.0






c pthreads






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 5 at 2:15









Grant Petty

241112




241112








  • 2




    You are describing a thread pool. Usually, instead of creating and destroying threads, you will create them all at once and then use some sort of queue to distribute work amongst them. Some technologies will do this for you at compile-time (e.g. OpenMP).
    – paddy
    Nov 5 at 2:31










  • See my proposed solution below.
    – Grant Petty
    Nov 5 at 3:32














  • 2




    You are describing a thread pool. Usually, instead of creating and destroying threads, you will create them all at once and then use some sort of queue to distribute work amongst them. Some technologies will do this for you at compile-time (e.g. OpenMP).
    – paddy
    Nov 5 at 2:31










  • See my proposed solution below.
    – Grant Petty
    Nov 5 at 3:32








2




2




You are describing a thread pool. Usually, instead of creating and destroying threads, you will create them all at once and then use some sort of queue to distribute work amongst them. Some technologies will do this for you at compile-time (e.g. OpenMP).
– paddy
Nov 5 at 2:31




You are describing a thread pool. Usually, instead of creating and destroying threads, you will create them all at once and then use some sort of queue to distribute work amongst them. Some technologies will do this for you at compile-time (e.g. OpenMP).
– paddy
Nov 5 at 2:31












See my proposed solution below.
– Grant Petty
Nov 5 at 3:32




See my proposed solution below.
– Grant Petty
Nov 5 at 3:32












1 Answer
1






active

oldest

votes

















up vote
0
down vote













After posting my question, I worked out what seems to be an acceptable, if possibly naive, solution (before I knew that the best approach is a thread pool; see paddy's comment above). It basically requires some bookkeeping, including the passing of additional variables to the threaded process. Here's what I came up with:



struct arg_struct {
double x ;
double y ;
int ithread ;
int loopno ;
};

const int MINLOOPS = 10 ; // total number of loops to execute
const int MAXTHREADS = 4 ; // maximum number of threads at any one time
pthread_t tid[MAXTHREADS] ; // table of active threads

int loopno = 0 ; // initialize loop counter
int nthreads = 0 ; // current number of active threads

void process(struct arg_struct *args)
{
int loopno,ithread ;
float x,y ;
x = args->x ; y = args->y ; ithread = args->ithread ; loopno = args->loopno ;
free(args) ; // we're done with passed arguments

sleep(MINLOOPS-loopno+1) ; // variable delay
printf("thisloop = %d threadID = %d args = %.1f %.1f ithread = %dn", loopno, (int) pthread_self(), x, y, ithread) ;

nthreads-- ; // done with current thread
tid[ithread] = 0 ;
pthread_exit(NULL); // exit thread
}

int main()
{
int ithread ;

for (ithread=0; ithread<MAXTHREADS; ithread++) tid[ithread] = 0 ; // initialize thread table

while (loopno < MINLOOPS)
{
if (nthreads < MAXTHREADS) { // check whether new thread needed
for (int ith=0; ith<MAXTHREADS; ith++) // find empty table entry
{
if (tid[ith] == 0) {
ithread = ith ;
break ;
}
}

struct arg_struct *args = malloc(sizeof(struct arg_struct)); // initialize arguments

loopno++ ;
args->x = loopno; args->y = -loopno ; args->ithread = ithread ; args->loopno = loopno ;
pthread_create(&tid[ithread], NULL, (void *) process, (void *) args ) ;
nthreads++ ;
printf("Created thread %dn", (int) tid[ithread]) ;
}
}

for (int i = 0; i < MAXTHREADS; i++) // wait until remaining threads have completed
pthread_join(tid[i], NULL) ;

}


The output is then:



Created thread 82550784
Created thread 83087360
Created thread 83623936
Created thread 84160512
thisloop = 4 threadID = 84160512 args = 4.0 -4.0 ithread = 3
Created thread 84697088
thisloop = 3 threadID = 83623936 args = 3.0 -3.0 ithread = 2
Created thread 85233664
thisloop = 2 threadID = 83087360 args = 2.0 -2.0 ithread = 1
Created thread 85770240
thisloop = 1 threadID = 82550784 args = 1.0 -1.0 ithread = 0
Created thread 86306816
thisloop = 7 threadID = 85770240 args = 7.0 -7.0 ithread = 1
Created thread 86843392
thisloop = 6 threadID = 85233664 args = 6.0 -6.0 ithread = 2
Created thread 87379968
thisloop = 8 threadID = 86306816 args = 8.0 -8.0 ithread = 0
thisloop = 5 threadID = 84697088 args = 5.0 -5.0 ithread = 3
thisloop = 10 threadID = 87379968 args = 10.0 -10.0 ithread = 2
thisloop = 9 threadID = 86843392 args = 9.0 -9.0 ithread = 1





share|improve this answer























  • The one thing I'm not sure I like about the above solution is that when the max number of threads are active, the 'while' loop spins away, presumably chewing up CPU cycles that could be used for something else. Adding a 'sleep' inside the loop might be counterproductive if its length is comparable to the average execution time of a thread. I'm not sure whether there's a way around that.
    – Grant Petty
    Nov 5 at 3:27






  • 1




    To avoid a spin-loop, you need to use thread synchronization primitives such as mutexes and semaphores.
    – paddy
    Nov 5 at 3:42










  • Thanks. I don't know what either of those terms mean (I'm new to multi-threading), so I'll have to do some more homework.
    – Grant Petty
    Nov 5 at 3:56











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53147464%2fc-maintaining-n-simultaneous-pthreads-at-a-time-for-mn-independent-calculatio%23new-answer', 'question_page');
}
);

Post as a guest
































1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
0
down vote













After posting my question, I worked out what seems to be an acceptable, if possibly naive, solution (before I knew that the best approach is a thread pool; see paddy's comment above). It basically requires some bookkeeping, including the passing of additional variables to the threaded process. Here's what I came up with:



struct arg_struct {
double x ;
double y ;
int ithread ;
int loopno ;
};

const int MINLOOPS = 10 ; // total number of loops to execute
const int MAXTHREADS = 4 ; // maximum number of threads at any one time
pthread_t tid[MAXTHREADS] ; // table of active threads

int loopno = 0 ; // initialize loop counter
int nthreads = 0 ; // current number of active threads

void process(struct arg_struct *args)
{
int loopno,ithread ;
float x,y ;
x = args->x ; y = args->y ; ithread = args->ithread ; loopno = args->loopno ;
free(args) ; // we're done with passed arguments

sleep(MINLOOPS-loopno+1) ; // variable delay
printf("thisloop = %d threadID = %d args = %.1f %.1f ithread = %dn", loopno, (int) pthread_self(), x, y, ithread) ;

nthreads-- ; // done with current thread
tid[ithread] = 0 ;
pthread_exit(NULL); // exit thread
}

int main()
{
int ithread ;

for (ithread=0; ithread<MAXTHREADS; ithread++) tid[ithread] = 0 ; // initialize thread table

while (loopno < MINLOOPS)
{
if (nthreads < MAXTHREADS) { // check whether new thread needed
for (int ith=0; ith<MAXTHREADS; ith++) // find empty table entry
{
if (tid[ith] == 0) {
ithread = ith ;
break ;
}
}

struct arg_struct *args = malloc(sizeof(struct arg_struct)); // initialize arguments

loopno++ ;
args->x = loopno; args->y = -loopno ; args->ithread = ithread ; args->loopno = loopno ;
pthread_create(&tid[ithread], NULL, (void *) process, (void *) args ) ;
nthreads++ ;
printf("Created thread %dn", (int) tid[ithread]) ;
}
}

for (int i = 0; i < MAXTHREADS; i++) // wait until remaining threads have completed
pthread_join(tid[i], NULL) ;

}


The output is then:



Created thread 82550784
Created thread 83087360
Created thread 83623936
Created thread 84160512
thisloop = 4 threadID = 84160512 args = 4.0 -4.0 ithread = 3
Created thread 84697088
thisloop = 3 threadID = 83623936 args = 3.0 -3.0 ithread = 2
Created thread 85233664
thisloop = 2 threadID = 83087360 args = 2.0 -2.0 ithread = 1
Created thread 85770240
thisloop = 1 threadID = 82550784 args = 1.0 -1.0 ithread = 0
Created thread 86306816
thisloop = 7 threadID = 85770240 args = 7.0 -7.0 ithread = 1
Created thread 86843392
thisloop = 6 threadID = 85233664 args = 6.0 -6.0 ithread = 2
Created thread 87379968
thisloop = 8 threadID = 86306816 args = 8.0 -8.0 ithread = 0
thisloop = 5 threadID = 84697088 args = 5.0 -5.0 ithread = 3
thisloop = 10 threadID = 87379968 args = 10.0 -10.0 ithread = 2
thisloop = 9 threadID = 86843392 args = 9.0 -9.0 ithread = 1





share|improve this answer























  • The one thing I'm not sure I like about the above solution is that when the max number of threads are active, the 'while' loop spins away, presumably chewing up CPU cycles that could be used for something else. Adding a 'sleep' inside the loop might be counterproductive if its length is comparable to the average execution time of a thread. I'm not sure whether there's a way around that.
    – Grant Petty
    Nov 5 at 3:27






  • 1




    To avoid a spin-loop, you need to use thread synchronization primitives such as mutexes and semaphores.
    – paddy
    Nov 5 at 3:42










  • Thanks. I don't know what either of those terms mean (I'm new to multi-threading), so I'll have to do some more homework.
    – Grant Petty
    Nov 5 at 3:56















up vote
0
down vote













After posting my question, I worked out what seems to be an acceptable, if possibly naive, solution (before I knew that the best approach is a thread pool; see paddy's comment above). It basically requires some bookkeeping, including the passing of additional variables to the threaded process. Here's what I came up with:



struct arg_struct {
double x ;
double y ;
int ithread ;
int loopno ;
};

const int MINLOOPS = 10 ; // total number of loops to execute
const int MAXTHREADS = 4 ; // maximum number of threads at any one time
pthread_t tid[MAXTHREADS] ; // table of active threads

int loopno = 0 ; // initialize loop counter
int nthreads = 0 ; // current number of active threads

void process(struct arg_struct *args)
{
int loopno,ithread ;
float x,y ;
x = args->x ; y = args->y ; ithread = args->ithread ; loopno = args->loopno ;
free(args) ; // we're done with passed arguments

sleep(MINLOOPS-loopno+1) ; // variable delay
printf("thisloop = %d threadID = %d args = %.1f %.1f ithread = %dn", loopno, (int) pthread_self(), x, y, ithread) ;

nthreads-- ; // done with current thread
tid[ithread] = 0 ;
pthread_exit(NULL); // exit thread
}

int main()
{
int ithread ;

for (ithread=0; ithread<MAXTHREADS; ithread++) tid[ithread] = 0 ; // initialize thread table

while (loopno < MINLOOPS)
{
if (nthreads < MAXTHREADS) { // check whether new thread needed
for (int ith=0; ith<MAXTHREADS; ith++) // find empty table entry
{
if (tid[ith] == 0) {
ithread = ith ;
break ;
}
}

struct arg_struct *args = malloc(sizeof(struct arg_struct)); // initialize arguments

loopno++ ;
args->x = loopno; args->y = -loopno ; args->ithread = ithread ; args->loopno = loopno ;
pthread_create(&tid[ithread], NULL, (void *) process, (void *) args ) ;
nthreads++ ;
printf("Created thread %dn", (int) tid[ithread]) ;
}
}

for (int i = 0; i < MAXTHREADS; i++) // wait until remaining threads have completed
pthread_join(tid[i], NULL) ;

}


The output is then:



Created thread 82550784
Created thread 83087360
Created thread 83623936
Created thread 84160512
thisloop = 4 threadID = 84160512 args = 4.0 -4.0 ithread = 3
Created thread 84697088
thisloop = 3 threadID = 83623936 args = 3.0 -3.0 ithread = 2
Created thread 85233664
thisloop = 2 threadID = 83087360 args = 2.0 -2.0 ithread = 1
Created thread 85770240
thisloop = 1 threadID = 82550784 args = 1.0 -1.0 ithread = 0
Created thread 86306816
thisloop = 7 threadID = 85770240 args = 7.0 -7.0 ithread = 1
Created thread 86843392
thisloop = 6 threadID = 85233664 args = 6.0 -6.0 ithread = 2
Created thread 87379968
thisloop = 8 threadID = 86306816 args = 8.0 -8.0 ithread = 0
thisloop = 5 threadID = 84697088 args = 5.0 -5.0 ithread = 3
thisloop = 10 threadID = 87379968 args = 10.0 -10.0 ithread = 2
thisloop = 9 threadID = 86843392 args = 9.0 -9.0 ithread = 1





share|improve this answer























  • The one thing I'm not sure I like about the above solution is that when the max number of threads are active, the 'while' loop spins away, presumably chewing up CPU cycles that could be used for something else. Adding a 'sleep' inside the loop might be counterproductive if its length is comparable to the average execution time of a thread. I'm not sure whether there's a way around that.
    – Grant Petty
    Nov 5 at 3:27






  • 1




    To avoid a spin-loop, you need to use thread synchronization primitives such as mutexes and semaphores.
    – paddy
    Nov 5 at 3:42










  • Thanks. I don't know what either of those terms mean (I'm new to multi-threading), so I'll have to do some more homework.
    – Grant Petty
    Nov 5 at 3:56













up vote
0
down vote










up vote
0
down vote









After posting my question, I worked out what seems to be an acceptable, if possibly naive, solution (before I knew that the best approach is a thread pool; see paddy's comment above). It basically requires some bookkeeping, including the passing of additional variables to the threaded process. Here's what I came up with:



struct arg_struct {
double x ;
double y ;
int ithread ;
int loopno ;
};

const int MINLOOPS = 10 ; // total number of loops to execute
const int MAXTHREADS = 4 ; // maximum number of threads at any one time
pthread_t tid[MAXTHREADS] ; // table of active threads

int loopno = 0 ; // initialize loop counter
int nthreads = 0 ; // current number of active threads

void process(struct arg_struct *args)
{
int loopno,ithread ;
float x,y ;
x = args->x ; y = args->y ; ithread = args->ithread ; loopno = args->loopno ;
free(args) ; // we're done with passed arguments

sleep(MINLOOPS-loopno+1) ; // variable delay
printf("thisloop = %d threadID = %d args = %.1f %.1f ithread = %dn", loopno, (int) pthread_self(), x, y, ithread) ;

nthreads-- ; // done with current thread
tid[ithread] = 0 ;
pthread_exit(NULL); // exit thread
}

int main()
{
int ithread ;

for (ithread=0; ithread<MAXTHREADS; ithread++) tid[ithread] = 0 ; // initialize thread table

while (loopno < MINLOOPS)
{
if (nthreads < MAXTHREADS) { // check whether new thread needed
for (int ith=0; ith<MAXTHREADS; ith++) // find empty table entry
{
if (tid[ith] == 0) {
ithread = ith ;
break ;
}
}

struct arg_struct *args = malloc(sizeof(struct arg_struct)); // initialize arguments

loopno++ ;
args->x = loopno; args->y = -loopno ; args->ithread = ithread ; args->loopno = loopno ;
pthread_create(&tid[ithread], NULL, (void *) process, (void *) args ) ;
nthreads++ ;
printf("Created thread %dn", (int) tid[ithread]) ;
}
}

for (int i = 0; i < MAXTHREADS; i++) // wait until remaining threads have completed
pthread_join(tid[i], NULL) ;

}


The output is then:



Created thread 82550784
Created thread 83087360
Created thread 83623936
Created thread 84160512
thisloop = 4 threadID = 84160512 args = 4.0 -4.0 ithread = 3
Created thread 84697088
thisloop = 3 threadID = 83623936 args = 3.0 -3.0 ithread = 2
Created thread 85233664
thisloop = 2 threadID = 83087360 args = 2.0 -2.0 ithread = 1
Created thread 85770240
thisloop = 1 threadID = 82550784 args = 1.0 -1.0 ithread = 0
Created thread 86306816
thisloop = 7 threadID = 85770240 args = 7.0 -7.0 ithread = 1
Created thread 86843392
thisloop = 6 threadID = 85233664 args = 6.0 -6.0 ithread = 2
Created thread 87379968
thisloop = 8 threadID = 86306816 args = 8.0 -8.0 ithread = 0
thisloop = 5 threadID = 84697088 args = 5.0 -5.0 ithread = 3
thisloop = 10 threadID = 87379968 args = 10.0 -10.0 ithread = 2
thisloop = 9 threadID = 86843392 args = 9.0 -9.0 ithread = 1





share|improve this answer














After posting my question, I worked out what seems to be an acceptable, if possibly naive, solution (before I knew that the best approach is a thread pool; see paddy's comment above). It basically requires some bookkeeping, including the passing of additional variables to the threaded process. Here's what I came up with:



struct arg_struct {
double x ;
double y ;
int ithread ;
int loopno ;
};

const int MINLOOPS = 10 ; // total number of loops to execute
const int MAXTHREADS = 4 ; // maximum number of threads at any one time
pthread_t tid[MAXTHREADS] ; // table of active threads

int loopno = 0 ; // initialize loop counter
int nthreads = 0 ; // current number of active threads

void process(struct arg_struct *args)
{
int loopno,ithread ;
float x,y ;
x = args->x ; y = args->y ; ithread = args->ithread ; loopno = args->loopno ;
free(args) ; // we're done with passed arguments

sleep(MINLOOPS-loopno+1) ; // variable delay
printf("thisloop = %d threadID = %d args = %.1f %.1f ithread = %dn", loopno, (int) pthread_self(), x, y, ithread) ;

nthreads-- ; // done with current thread
tid[ithread] = 0 ;
pthread_exit(NULL); // exit thread
}

int main()
{
int ithread ;

for (ithread=0; ithread<MAXTHREADS; ithread++) tid[ithread] = 0 ; // initialize thread table

while (loopno < MINLOOPS)
{
if (nthreads < MAXTHREADS) { // check whether new thread needed
for (int ith=0; ith<MAXTHREADS; ith++) // find empty table entry
{
if (tid[ith] == 0) {
ithread = ith ;
break ;
}
}

struct arg_struct *args = malloc(sizeof(struct arg_struct)); // initialize arguments

loopno++ ;
args->x = loopno; args->y = -loopno ; args->ithread = ithread ; args->loopno = loopno ;
pthread_create(&tid[ithread], NULL, (void *) process, (void *) args ) ;
nthreads++ ;
printf("Created thread %dn", (int) tid[ithread]) ;
}
}

for (int i = 0; i < MAXTHREADS; i++) // wait until remaining threads have completed
pthread_join(tid[i], NULL) ;

}


The output is then:



Created thread 82550784
Created thread 83087360
Created thread 83623936
Created thread 84160512
thisloop = 4 threadID = 84160512 args = 4.0 -4.0 ithread = 3
Created thread 84697088
thisloop = 3 threadID = 83623936 args = 3.0 -3.0 ithread = 2
Created thread 85233664
thisloop = 2 threadID = 83087360 args = 2.0 -2.0 ithread = 1
Created thread 85770240
thisloop = 1 threadID = 82550784 args = 1.0 -1.0 ithread = 0
Created thread 86306816
thisloop = 7 threadID = 85770240 args = 7.0 -7.0 ithread = 1
Created thread 86843392
thisloop = 6 threadID = 85233664 args = 6.0 -6.0 ithread = 2
Created thread 87379968
thisloop = 8 threadID = 86306816 args = 8.0 -8.0 ithread = 0
thisloop = 5 threadID = 84697088 args = 5.0 -5.0 ithread = 3
thisloop = 10 threadID = 87379968 args = 10.0 -10.0 ithread = 2
thisloop = 9 threadID = 86843392 args = 9.0 -9.0 ithread = 1






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 5 at 3:28

























answered Nov 5 at 3:20









Grant Petty

241112




241112












  • The one thing I'm not sure I like about the above solution is that when the max number of threads are active, the 'while' loop spins away, presumably chewing up CPU cycles that could be used for something else. Adding a 'sleep' inside the loop might be counterproductive if its length is comparable to the average execution time of a thread. I'm not sure whether there's a way around that.
    – Grant Petty
    Nov 5 at 3:27






  • 1




    To avoid a spin-loop, you need to use thread synchronization primitives such as mutexes and semaphores.
    – paddy
    Nov 5 at 3:42










  • Thanks. I don't know what either of those terms mean (I'm new to multi-threading), so I'll have to do some more homework.
    – Grant Petty
    Nov 5 at 3:56


















  • The one thing I'm not sure I like about the above solution is that when the max number of threads are active, the 'while' loop spins away, presumably chewing up CPU cycles that could be used for something else. Adding a 'sleep' inside the loop might be counterproductive if its length is comparable to the average execution time of a thread. I'm not sure whether there's a way around that.
    – Grant Petty
    Nov 5 at 3:27






  • 1




    To avoid a spin-loop, you need to use thread synchronization primitives such as mutexes and semaphores.
    – paddy
    Nov 5 at 3:42










  • Thanks. I don't know what either of those terms mean (I'm new to multi-threading), so I'll have to do some more homework.
    – Grant Petty
    Nov 5 at 3:56
















The one thing I'm not sure I like about the above solution is that when the max number of threads are active, the 'while' loop spins away, presumably chewing up CPU cycles that could be used for something else. Adding a 'sleep' inside the loop might be counterproductive if its length is comparable to the average execution time of a thread. I'm not sure whether there's a way around that.
– Grant Petty
Nov 5 at 3:27




The one thing I'm not sure I like about the above solution is that when the max number of threads are active, the 'while' loop spins away, presumably chewing up CPU cycles that could be used for something else. Adding a 'sleep' inside the loop might be counterproductive if its length is comparable to the average execution time of a thread. I'm not sure whether there's a way around that.
– Grant Petty
Nov 5 at 3:27




1




1




To avoid a spin-loop, you need to use thread synchronization primitives such as mutexes and semaphores.
– paddy
Nov 5 at 3:42




To avoid a spin-loop, you need to use thread synchronization primitives such as mutexes and semaphores.
– paddy
Nov 5 at 3:42












Thanks. I don't know what either of those terms mean (I'm new to multi-threading), so I'll have to do some more homework.
– Grant Petty
Nov 5 at 3:56




Thanks. I don't know what either of those terms mean (I'm new to multi-threading), so I'll have to do some more homework.
– Grant Petty
Nov 5 at 3:56


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53147464%2fc-maintaining-n-simultaneous-pthreads-at-a-time-for-mn-independent-calculatio%23new-answer', 'question_page');
}
);

Post as a guest




















































































這個網誌中的熱門文章

Tangent Lines Diagram Along Smooth Curve

Yusuf al-Mu'taman ibn Hud

Zucchini