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
}
Related
I am trying to pass a pointer to a funcion, and in that function create an array, and set the passed pointer to that array.
What I'm trying to do is create an array inside the function and then use that array outside the funcion.
void createArray(int *myPointer)
{
int intArray[20];
*myPointer = &intArray[0]; // This line gets error:
// assignment makes integer from pointer without a cast [-Wint-conversion]
for (int i = 0; i < 20; i++)
{
intArray[i] = i + 10;
}
}
int main(void)
{
int *intPointer;
createArray(&intPointer);
for (int i = 0; i < 20; i++)
{
printf("%d : %d \n", i, intPointer[i]);
}
return 0;
}
You meant to use
void createArray(int **myPointer)
That will resolve the two type errors.
But that will make main's pointer point to a variable that no longer exists after createArray returns. That's bad. And that's why you have to use malloc instead of automatic storage.
void createArray( int **myPointer ) {
int *intArray = malloc( 20 * sizeof(int) );
*myPointer = intArray; // Same as `&intArray[0]`
if ( !intArray )
return;
for ( int i = 0; i < 20; i++ )
intArray[i] = i + 10;
}
int main(void) {
int *intPointer;
createArray(&intPointer);
if ( intPointer ) {
perror( NULL );
exit( 1 );
}
for (int i = 0; i < 20; i++)
printf( "%d: %d\n", i, intPointer[i] );
return 0;
}
The reason for the compiler error is the *myPointer dereferencing, which gives you the content of type int that the pointer points at. The compiler is saying that you can't assign the pointer &intArray[0] to a plain int.
Besides being invalid C, it wouldn't change where the pointer points. To do that, you would have to do myPointer = &intArray[0];. However, in this case you can't do that either because the myPointer is just a local pointer variable inside the function - a local copy of the pointer you passed. You need a way to update the pointer in main().
Furthermore, we can never return a pointer to local data (data with "automatic storage duration") because that data ceases to be valid as soon as we leave the function.
The normal solution is to create dynamically allocated memory instead, since such memory persists throughout the execution of the program (or until you explicitly free it). There are two different ways to write a function for that:
#include <stdlib.h> // for malloc
int* createArray (void)
{
int* result = malloc(20 * sizeof(*result));
if(result == NULL)
return NULL; // some error handling will be required here
for (int i = 0; i < 20; i++)
{
result[i] = i + 10;
}
return result;
}
...
int *intPointer = createArray();
...
free(intPointer);
Alternatively you could pass the pointer itself by value, so that by doing the *myPointer = ...; assignment, you refer to where a int** points at:
#include <stdlib.h> // for malloc
void createArray (int** myPointer)
{
int* result;
result = malloc(20 * sizeof(*result));
if(result == NULL)
{
/* some error handling will be required here */
}
for (int i = 0; i < 20; i++)
{
result[i] = i + 10;
}
*myPointer = result;
}
...
int *intPointer;
createArray(&intPointer);
...
free(intPointer);
Either of these are ok and which one you use is mostly a matter of design. It's easier syntax to have the pointer returned, but then normally the return of functions is reserved for some error code.
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;
}
I am trying to pass a 2d array into a pthread function, but I can not find a way to get access to the array content during pthread process, how can I do it?
I tried
int ** array = (int **)arg;
but it caused segfault after I tried to change the stored value;
Here is part of my code:
int message1[2][64];
int i = 0;
for (; i < 2; i++)
{
int j = 0;
for (; j < 64; j++)
{
message[i][j] = 1;
}
}
pthread_t tid[1];
pthread_create(&tid[0], NULL, xD, message);
the function:
void * xD(void * arg)
{
int ** array = (int **)arg;
array[0][0] = 2;
}
Couldn't find a proper duplicate for this. int ** is not a 2D array but a pointer to a pointer to an int.
What you want to pass in is a pointer to an array[64] of int, i.e. int (*array)[64].
Try
int (*array)[64] = arg;
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;
}
#include <stdio.h>
#include <stdlib.h>
void setZero (double **, int);
int main (void) {
double *ptr = NULL;
int i, size = 3;
ptr = (double *)malloc(size * sizeof(double));
//*
setZero(&ptr, size);
/*/
// Sanity test
for ( i = 0 ; i < size ; ++i ) {
printf("index %d/%d\n", i, (size-1));
ptr[i] = 0; // NOT EXPLODING...
}
//*/
free(ptr);
return 0;
}
void setZero (double **_ref_array, int _size) {
int i;
for ( i = 0 ; i < _size; ++i ) {
printf("index %d/%d\n", i, (_size-1));
*_ref_array[i] = 0; // EXPLODING...
}
}
1) Why is this not working?
2) What is a "Bus error 10"
P.S. I know better than to initialize an array this way, but this just happens to be a simple and clean example of an underlying concept that I'm not understanding...
The dereference is happening after the index. I.e.
This says "Get the double pointer at index 'i', then set the value 0 to the memory at the address within that pointer."
*_ref_array[i] = 0;
This says "Get the address of the array of doubles from _ref_array, than index off that address by i-doubles.
(*_ref_array)[i] = 0;
On the face of the code given, you don't need to pass the address of the pointer to the function. You should be using:
void setZero(double *ptr, int size)
{
for (int i = 0; i < size; i++)
ptr[i] = 0.0;
}
and:
setZero(ptr, size);
The trouble you've got is as WhozCraig says:
*_array_ref[i]
is interpreted as:
*(_array_ref[i])
instead of:
(*_array_ref)[i]
as you need it to be. The former is trampling up the stack; the latter is initializing the allocated memory.
If you really must pass a pointer to a pointer to the function, then you can either wrap parentheses around the dereferences, or you can assign a local pointer and use that normally, right up to the point where you need to make use of the double pointer to change the value in the calling function.
void setZero(double **ptr, int size)
{
double *base = *ptr;
for (int i = 0; i < size; i++)
{
base[i] = 0.0;
// Or: (*ptr)[i] = 0.0;
}
...presumably some code here needs to assign to *ptr...
...if there is no such code, there is no need of the double pointer...
}