I'm working in C, and I'm trying to pass in a pointer to an array that will hold my thread ids, but I cannot seem to get my types to match. What am I not understanding about passing pointers in C?
This is my function:
int createThreads(int numThreads, pthread_t **tidarray) {
pthread_t *tids = *tidarray;
int i;
for (i = 0; i < numThreads; i++) {
pthread_create(tids + i, NULL, someFunction, NULL);
}
return 0;
}
And this is my call:
pthread_t tids[numThreads];
createThreads(5, &tids);
When I compile this, I get a warning:
Passing argument 2 of 'createThreads' from incompatible pointer type, and
Note: expected 'pthread_t **' but argument is of type 'pthread_t (*) [(long unsigned int)(numThreads)]'
#include <stdio.h>
#include <pthread.h>
// dummy function for threads , it just print its argument
void * someFunction(void *data){
printf("Thread %d\n",(int)data);
}
int createThreads(int numThreads, pthread_t *tidarray) {
int i;
for (i = 0; i < numThreads; i++) {
//pass the pointer of the first element + the offset i
pthread_create(tidarray+i, NULL, someFunction, (void*)i);
}
return 0;
}
int main(){
pthread_t tids[5]={0};// initialize all to zero
createThreads(5, tids);
getchar();// give time to threads to do their job
// proof-of-concept, the array has been filled by threads ID
for(int i=0;i<5;i++)
printf("Thread (%d) ID = %u\n",i,tids[i]);
return 0;
}
You don't need the & address of operator, just pass it as it is because it's converted to a pointer automatically, so
createThreads(5, tids);
is what you need, and then your createThreads() function
int createThreads(int numThreads, pthread_t *tids)
{
int i;
for (i = 0; i < numThreads; i++)
{
pthread_create(tids + i, NULL, someFunction, NULL);
}
return 0;
}
Related
As you can see, when I cast int to void* and then cast it back to int, the value is not the same, and I encounter a segmentation fault. What is the problem with this? I also tried int j = *(int*)i and it fails, too.
void* run(void* i)
{
// some code
uintptr_t j = (intptr_t)(void*)i;
// some code
}
int main()
{
// some code
for (int i = 0; i < THREADS; i++)
{
void *pointer = &i;
pthread_create(&threads[i], NULL, run, pointer);
}
// some code
}
when I cast int to void* ...
You are not actually doing that. Your run() function is expecting you to cast the value of i to a void*, but your main() loop is instead assigning the address of i to a void*. Big difference.
The reason why int j = *(int*)i fails (although it is syntactically correct when using void *pointer = &i;) is because you are making all of the threads act on a single int variable in memory. That int is changing value on each loop iteration in main(), without telling the threads that it is changing. And worse, the lifetime of that int ends as soon as the loop ends, leaving each thread with a dangling pointer.
If you want each thread to act on its own int value, you need to pass around the value of i, not the address of i, eg:
void* run(void* arg)
{
// some code
int j = (int)(intptr_t)arg;
// some code
}
int main()
{
// some code
for (int i = 0; i < THREADS; i++)
{
void *pointer = (void*)(intptr_t)i;
pthread_create(&threads[i], NULL, run, pointer);
}
// some code
for (int i = 0; i < THREADS; i++)
pthread_join(&threads[i], NULL);
// some code
}
Alternatively, allocate a separate int for each thread, and then pass the address of each thread's int, eg:
void* run(void* arg)
{
// some code
int j = *(int*)arg;
// some code
}
int main()
{
// some code
int arr[THREADS];
for (int i = 0; i < THREADS; i++)
{
arr[i] = i;
void *pointer = &arr[i];
pthread_create(&threads[i], NULL, run, pointer);
}
// some code
for (int i = 0; i < THREADS; i++)
pthread_join(&threads[i], NULL);
// some code
}
I am trying to sum up 1000 elements integer array(where each element is 1) with pthread library by splitting the array in to segments of size 10. So effectively, 100 threads are being used to do that. The results of this parallel operation is as expected (1000). But interestingly, the sequential sum which I calculated before creating the threads is being set to zero after my first call to pthread_join(). Not sure if I am missing something here. Can someone spot the bug here?
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define SEGMENT_SIZE 10
#define NUM_THREADS 100
int *array = NULL;
void* segment_sum(void *args)
{
int index = (int)args;
int sum = 0;
for (int i = index * SEGMENT_SIZE; i < (index + 1) * SEGMENT_SIZE; i++) {
sum += array[i];
}
return (void *)sum;
}
int main()
{
pthread_t thread[NUM_THREADS];
int res = 0;
int seq_res = 0;
int par_res = 0;
array = calloc(1, sizeof(int) * NUM_THREADS * SEGMENT_SIZE);
for (int i = 0; i < NUM_THREADS * SEGMENT_SIZE; i++) {
array[i] = 1;
seq_res += 1;
}
for (int i = 0; i < NUM_THREADS; i++) {
res = pthread_create(&thread[i], NULL, segment_sum, (void *)i);
if (res != 0) {
printf("\nError creating new thread");
}
}
printf("\nindex = %d", seq_res); // the sequential sum here is 1000
for (int i = 0; i < NUM_THREADS; i++) {
int sum = 0;
res = pthread_join(thread[i], (void **)&sum);
if (res != 0) {
printf("\nError creating new thread");
}
printf("\nindex = %d", seq_res); // Here it is becoming zero!!!
par_res += sum;
}
printf("\nmultithreaded sum: %d single threaded sum: %d\n", par_res, seq_res);
}
When you compile your program, try as much as possible to eliminate
the warnings as they often point out non portable behaviors or hidden
errors. Here the compilation points out the following:
pte.c: In function 'segment_sum':
pte.c:11:21: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
11 | int index = (int)args;
| ^
pte.c:18:16: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
18 | return (void *)sum;
| ^
pte.c: In function 'main':
pte.c:36:69: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
36 | res = pthread_create(&thread[i], NULL, segment_sum, (void *)i);
| ^
The parameter passed to the threads is a cast of a pointer into an "int". It is
advised to pass the address of an "int". Hence, you can define a per-thread
context:
struct thd_ctx {
pthread_t thread;
int index;
int sum;
};
pthread_join() is passed the address of a pointer which will get the address
of the memory location into which the thread stored its result. The thread must
return the address of this memory location, not the value stored into it.
Moreover, the thread should not return the address of an automatic variable
(i.e. in its stack) as it is unspecified. The result must be the address
of a global variable (or "something" visible from the joining thread) returned either directly or through pthread_exit(). In this enhancement of the program, we use the address of the "sum" field in the thread's context:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#define SEGMENT_SIZE 10
#define NUM_THREADS 100
int *array = NULL;
struct thd_ctx {
pthread_t thread;
int index;
int sum;
};
void *segment_sum(void *args)
{
int i;
struct thd_ctx *ctx = (struct thd_ctx *)args;
ctx->sum = 0;
for (i = ctx->index * SEGMENT_SIZE; i < (ctx->index + 1) * SEGMENT_SIZE; i++) {
ctx->sum += array[i];
}
return (void *)&(ctx->sum);
}
int main(void)
{
struct thd_ctx thd_ctx[NUM_THREADS];
int res = 0;
int seq_res = 0;
int par_res = 0;
int i;
array = calloc(1, sizeof(int) * NUM_THREADS * SEGMENT_SIZE);
if (!array) {
fprintf(stderr, "calloc(): error %d\n", errno);
return 1;
}
for (i = 0; i < NUM_THREADS * SEGMENT_SIZE; i++) {
array[i] = 1;
seq_res += 1;
}
for (i = 0; i < NUM_THREADS; i++) {
thd_ctx[i].index = i;
res = pthread_create(&(thd_ctx[i].thread), NULL, segment_sum, (void *)&(thd_ctx[i]));
if (res != 0) {
fprintf(stderr, "Error %d creating new thread#%d\n", res, i);
free(array);
return 1;
}
}
printf("Index = %d\n", seq_res); // the sequential sum here is 1000
for (i = 0; i < NUM_THREADS; i++) {
int *sum = 0;
res = pthread_join(thd_ctx[i].thread, (void **)&(sum));
if (res != 0) {
printf("Error %d joining thread#%d", res, i);
free(array);
return 1;
}
par_res += *sum;
printf("sum = %d\n", par_res);
}
printf("\nMultithreaded sum: %d single threaded sum: %d\n", par_res, seq_res);
free(array);
return 0;
}
I'm a beginner working on a C practice program that can calculate various statistical values for a list of numbers read in from the command line. But when trying to compile my code in Linux, I get a handful of errors that I'm not sure how to interpret, and was wondering if I could get some help from those more familiar with the C language than myself. I've included both my code and the errors below.
My code:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
int *values;
int size;
double avg=0.0;
int minValue=0;
int maxValue=0;
void *runAvg(void *param);
void *runMin(void *param);
void *runMax(void *param);
int main (int argc, char *argv[]){
if(argc != 2){
fprintf(stderr, "usage: %s <integer value>\n", argv[0]);
}
int i;
for(i=1; i < argc; i++){
values=&(atoi(argv[i]));
size++;
}
pthread_t avgPt[size];
pthread_t minPt[size];
pthread_t maxPt[size];
pthread_attr_t attr;
//create threads
pthread_create(&avgPt, &attr, runAvg, values);
pthread_create(&minPt, &attr, runMin, values);
pthread_create(&maxPt, &attr, runMax, values);
//wait for threads to exit
pthread_join(avgPt, NULL);
pthread_join(minPt, NULL);
pthread_join(maxPt, NULL);
//print results of threads
printf("\n Average: %f \n",avg);
printf("\n Minimum: %d \n",minValue);
printf("\n Maximum: %d \n",maxValue);
}
void *runAvg(void *param){
int sum=0;
int i=0;
int *values;
values=(int*)param;
for(i=0;i<size; i++) sum += values[i];
avg = sum / (double)size;
pthread_exit(0);
}
void *runMin(void *param){
int i=0;
int *values;
values=(int*)param;
minValue = values[0];
for(i=0;i<size;i++){
if(values[i]<minValue){
minValue=values[i];
}
}
pthread_exit(0);
}
void *runMax(void *param){
int i=0;
int *values;
values=(int*)param;
maxValue=values[0];
for(i=0;i<size;i++){
if(values[i] > maxValue){
maxValue = values[i];
}
}
pthread_exit(0);
}
My compile errors:
423assign.c:20: error: lvalue required as unary ‘&’ operand
423assign.c:30: warning: passing argument 1 of ‘pthread_create’ from
incompatible pointer type
/usr/include/pthread.h:227: note: expected ‘pthread_t * __restrict__’
but argument is of type ‘pthread_t (*)[(unsigned int)(size)]’
423assign.c:31: warning: passing argument 1 of ‘pthread_create’ from
incompatible pointer type
/usr/include/pthread.h:227: note: expected ‘pthread_t * __restrict__’
but argument is of type ‘pthread_t (*)[(unsigned int)(size)]’
423assign.c:32: warning: passing argument 1 of ‘pthread_create’ from
incompatible pointer type
/usr/include/pthread.h:227: note: expected ‘pthread_t * __restrict__’
but argument is of type ‘pthread_t (*)[(unsigned int)(size)]’
423assign.c:34: warning: passing argument 1 of ‘pthread_join’ makes
integer from pointer without a cast
/usr/include/pthread.h:244: note: expected ‘pthread_t’ but argument is
of type ‘pthread_t *’
423assign.c:35: warning: passing argument 1 of ‘pthread_join’ makes
integer from pointer without a cast
/usr/include/pthread.h:244: note: expected ‘pthread_t’ but argument is
of type ‘pthread_t *’
423assign.c:36: warning: passing argument 1 of ‘pthread_join’ makes
integer from pointer without a cast
/usr/include/pthread.h:244: note: expected ‘pthread_t’ but argument is
of type ‘pthread_t *’
Your thread functions were okay.
One issue was not allocating an int array to contain the values from atoi.
Also, your pthread_t variables should not be arrays. And your attr value is never initialized and not used.
Here's a cleaned up version with the bugs annotated and fixed [please pardon the gratuitous style cleanup]:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
int *values;
int size;
double avg = 0.0;
int minValue = 0;
int maxValue = 0;
void *runAvg(void *param);
void *runMin(void *param);
void *runMax(void *param);
int
main(int argc, char **argv)
{
// NOTE/BUG: this should be "< 2" and not "!= 2"
if (argc < 2) {
fprintf(stderr, "usage: %s <integer value>\n", argv[0]);
exit(1);
}
int i;
--argc;
++argv;
// NOTE/BUG: we must allocate an int array of sufficient size
values = calloc(argc,sizeof(int));
for (i = 0; i < argc; i++) {
values[i] = atoi(argv[i]);
size++;
}
// NOTE/BUG: these should _not_ be arrays
pthread_t avgPt;
pthread_t minPt;
pthread_t maxPt;
// NOTE/BUG: this is unitialized and it's not set to anything, so the
// pthread_create 2nd argument can [and should be] NULL
#if 0
pthread_attr_t attr;
#endif
// create threads
#if 0
pthread_create(&avgPt, &attr, runAvg, values);
pthread_create(&minPt, &attr, runMin, values);
pthread_create(&maxPt, &attr, runMax, values);
#else
pthread_create(&avgPt, NULL, runAvg, values);
pthread_create(&minPt, NULL, runMin, values);
pthread_create(&maxPt, NULL, runMax, values);
#endif
// wait for threads to exit
pthread_join(avgPt, NULL);
pthread_join(minPt, NULL);
pthread_join(maxPt, NULL);
// print results of threads
printf("\n Average: %f \n", avg);
printf("\n Minimum: %d \n", minValue);
printf("\n Maximum: %d \n", maxValue);
}
void *
runAvg(void *param)
{
int sum = 0;
int i = 0;
int *values;
values = param;
for (i = 0; i < size; i++)
sum += values[i];
avg = sum / (double) size;
return (void *) 0;
}
void *
runMin(void *param)
{
int i = 0;
int *values;
values = param;
minValue = values[0];
for (i = 0; i < size; i++) {
if (values[i] < minValue)
minValue = values[i];
}
return (void *) 0;
}
void *
runMax(void *param)
{
int i = 0;
int *values;
values = param;
maxValue = values[0];
for (i = 0; i < size; i++) {
if (values[i] > maxValue)
maxValue = values[i];
}
return (void *) 0;
}
I've been trying to get an array of ints back from a thread. I think I'm really close. The errors I'm getting are about dereferencing a void pointer and invalid use of a void expression here
assn3.c:29:29: error: dereferencing ‘void *’ pointer [-Werror]
printf(" %d", (int)answer[j]);
^
assn3.c:29:18: error: invalid use of void expression
printf(" %d", (int)answer[j]);
I've tried changing the return type of my functions to int* but it didn't seem to like that. What am I missing here?
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
void *getFactors(void *param);
int main(int argc, char *argv[])
{
for(int i = argc; i > 0; i--)
{
void *answer;
pthread_t tid;
pthread_attr_t attr;
if (atoi(argv[i])<0)
{
fprintf(stderr, "%d must be > 0\n", atoi(argv[i]));
return -1;
}
pthread_attr_init(&attr);
pthread_create(&tid, &attr, getFactors, argv[i]);
pthread_join(tid, &answer);
printf("%d", atoi(argv[i]));
printf(":");
for(int j = 0; j < sizeof(answer); j++)
{
printf(" %d", (int)answer[j]);
}
printf("\n");
}
}
And the thread function
void *getFactors(void *param)
{
int a[10];
int n = atoi(param);
int i = 0;
while (n%2 == 0)
{
a[i] = 2;
n/=2;
i++;
}
int f=3;
while (f * f <= n)
{
if (n % f == 0)
{
a[i]=f;
n /= f;
i++;
}
else
{
f += 2;
}
}
if (n<1)
{
a[i]=n;
i++;
}
int* buffer = (int*) malloc(i);
buffer = a;
return (void *) buffer;
pthread_exit(0);
}
void *answer;
...
int * answer_beeing_an_int_arr = answer;
printf(" %d", answer_beeing_an_int_arr[j]);
This is what you want. But you find that:
printf(" %d", (int)answer[j]);
does not work. Why you ask? It's because the cast (int) has lower precedence than the array subscript [j], and also you don't tell the compiler that answer is a pointer to ints, only that it should first get the value, then cast to int. You want this:
printf(" %d", ((int*)answer)[j]);
You want to tell the compiler, that the answer is a pointer to int. Then you want to add to that that pointer sizeof(int) * j bytes and dereference it.
And remember to free(answer).
Now to your code:
buffer = a;
is wrong. It assigns the pointer to another pointer. You want to copy the values behind the pointers, not pointers themselves. You need:
memcpy(buffer, a, sizeof(int) * i);
or
for (size_t j = 0; j < i; ++j) {
buffer[j] = a[j];
}
to copy array values.
... = malloc(i);
This will allocate i bytes. An int does not have 1 byte (CHAR_BIT bits, probably 8). It has more. It can be 2, can be more. sizeof(int) will tell you how many bytes an int has. So it has to be:
int *buffer = malloc(i * sizeof(int));
or as I like it:
int *buffer = malloc(i * sizeof(*buffer));
Also:
int* buffer = (int*) malloc(i);
...
return (void *) buffer;
No need to cast a pointer to void* and from void*. void* is a generic pointer, it's a pointer to nothing. Just:
int* buffer = malloc(i * sizeof(*buffer));
...
return buffer;
There are several things wrong here:
for(int j = 0; j < sizeof(answer); j++) // This will NOT tell you the #/elements in the array
pthread_join() is probably not the best way to pass back your integer buffer
And, of course, printf(" %d", (int)answer[j]); is a compile error :(
SUGGESTION:
Read through this tutorial, and restructure your code accordingly:
http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html
Or you can scan through this:
http://www.cs.kent.edu/~ruttan/sysprog/lectures/multi-thread/multi-thread.html
There are a few things you need to correct as pointed earlier.
As pointed, do not use a local variable as a return address. It will not be accessible when the thread returns. It is better to use a global variable and allocate memory dynamically. You can free it in the function which has created the thread.
For accessing variables which are changed by a thread, you can either pass it to the thread function using the fourth argument in pthread_create(3) and later access it. Or access it using pthread_join as a return value.
Might need to use a mutex or other synchronization primitives if multiple threads are accessing the variable.
One simple example of returning an array using pthread_join(3) is given below.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#define ARRAY_LEN 10
void *functionPthread(void *);
int *retArray;
int main()
{
int rc, i;
pthread_t th;
retArray = (int*) malloc(sizeof(int) *ARRAY_LEN);
if(rc = pthread_create(&th, NULL, &functionPthread, NULL))
{
printf("Thread creation failed, return code %d, errno %d", rc, errno);
}
pthread_join(th, (void**)&retArray);
for(i = 0; i < ARRAY_LEN; i++)
printf("%d ", retArray[i]);
printf("\n");
free(retArray);
return 0;
}
void *functionPthread(void *)
{
int i;
for(i = 0; i < ARRAY_LEN; i++)
retArray[i] = i;
return retArray;
}
So when I run my code, I'm getting a segmentation fault right at the pthread_join. There is a print statement after my pthread_join that doesn't run. Does anyone have any idea why? Could you give me some hints or ideas as to how to figure this out??
the output prints out all of row numbers for my matrix until the end, then it leaves matrixCalc function and prints "after threads are created". This happens when I put in an argument for 1 thread.
I've included a small section of my code here:
int main(int argc, char*argv[])
{
//takes in number of threads as 1st arg
pthread_attr_init(&attr);
//initialize matrix here
//passes num of threads through matrixcalc
for(i = 0; i < numberOfThreads; i++)
{
threadCount++;
pthread_create(&tid, &attr, matrixCalc(threadCount), NULL);
}
printf("after threads are created\n");
pthread_join(tid, NULL);
printf("after join\n");
exit(0);
return 0;
}
Here is matrix calc function:
void *matrixCalc(threadCount)
{
int i, j, sum, tempNum, currentRow;
currentRow = threadCount;
sum=0;
while(currentRow < 1200)
{
//cycles through the column j for matrix B
for(j=0; j<500; j++)
{
//cycles through the diff i values for the set row in matrix A and column in matrix B
for(i=0; i<1000; i++)
{
//Matrix A set i value is at threadcount-1
//Matrix B i value = j
//Matrix B j value = i
//Multiply together and add to sum
tempNum = (matrixA[currentRow-1][i])*(matrixB[i][j]);
sum = sum+tempNum;
}
//Set Matrix C at i value = currentRow and jvalue = i to sum
matrixC[currentRow-1][j] = sum;
//printf("%d\n", matrixC[currentRow-1][i]);
}
//increase threadcount by number of threads
//until you hit max/past max val
currentRow = currentRow + nThreads;
//printf("%d\n", currentRow);
}
return NULL;
}
When calling pthread_create() you need to pass the address of a function of type void *(*)(void *). What the code does is calling a function there so its result is getting passed to pthread_create().
Change this line
pthread_create(&tid, &attr, matrixCalc(threadCount), NULL);
to become
pthread_create(&tid, &attr, matrixCalc, NULL);
or
pthread_create(&tid, &attr, &matrixCalc, NULL);
which in fact is the same.
As already mentioned above the thread function needs to be declared as void *(*)(void *).
So change this
void *matrixCalc(threadCount)
will will become this
void * matrixCalc(void *)
As the code seems to try to spawn off multiple threads and all should be joined perpare room to store the several pthread-ids.
This could for example be done using an array like this:
pthread_t tid[numberOfThreads] = {0};
Then create the thread like this:
pthread_create(&tid[i], &attr, matrixCalc, NULL);
To passed the thread number (counter i) down to the thread also give it room by defining
int thread_counts[numberOfThreads] = {0};
assign it and pass it as 4th parameter on the thread's creation:
thread_counts[i] = i;
pthread_create(&tid[i], &attr, matrixCalc, &thread_Counts[i]);
Down in the thread function then get it by modifying
void *matrixCalc(threadCount)
{
int i, j, sum, tempNum, currentRow;
currentRow = threadCount;
...
like this:
void * matrixCalc(void * pv)
{
int i, j, sum, tempNum, currentRow;
currentRow = *((int*) pv);
...
Finally to join all thread replace the single call to pthread_join() by a loop:
for (i = 0; i < numberOfThreads; ++i)
{
pthread_join(tid[i], NULL);
}
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine) (void *), void *arg);
The third parameter is a start function taking a void ptr and returning a void ptr.
The fourth parameter takes a void ptr pointing to the data you want to pass, in this case threadcnt.