So I am trying to figure out why I am getting this error in regards to p thread.
I get the below error when I'm trying to run the code. I know it has to be something with p thread but not sure exactly what it is.
prime.c: In function ‘main’:
prime.c:33: warning: cast to pointer from integer of different size
prime.c: In function ‘isPrime’:
prime.c:50: warning: cast from pointer to integer of different size
any idea of what I'm doing wrong? I am including my code below. Thanks in advance for help.
#include<stdio.h>
#include<stdlib.h>
#include <pthread.h>
int *ptr;
int count;
int n;
void *isPrime(void *argp);
int main(int argc, char *argv[]) {
int i;
int num = 2;
int p;
pthread_t tid;
count = 0;
if (argc == 2 || argc == 3) {
printf("Argument : %s\n", argv[1]);
n = atoi(argv[1]);
if (argc == 3) {
p = atoi(argv[2]);
}
else {
p = 1;
}
ptr = (int *) malloc(n*sizeof(int));
while (count <= n) {
for (i = 1; i <= p; i++)
pthread_create(&tid, NULL, isPrime, (void *)num++);
}
for ( i = 0;i < n; i++) {
printf("%d ", *(ptr+i));
}
}
else {
printf("Invalid number of arguments\n");
}
}
void *isPrime(void *vargp) {
int i,flag = 0;
int num = (int)vargp;
for (i = 2; i <= num/2; i++) {
if (num % i == 0) {
flag = 1;
break;
}
}
if (!flag && count <= n) {
*(ptr + count) = num;
count++;
}
}
Here's the obvious way to avoid the implementation-defined behavior inherent in casting between integers and pointers:
while (count <= n) {
for (i = 1; i <= p; i++) {
int * iptr = malloc(sizeof *iptr);
if ( !iptr ) {
perror("Couldn't allocate memory."); /* Or other failure code */
exit(EXIT_FAILURE);
}
*iptr = num++;
pthread_create(&tid, NULL, isPrime, iptr);
}
}
and then in your thread function:
void *isPrime(void *vargp) {
int * iptr = vargp;
int num = *iptr;
free(iptr);
/* Rest of function */
return NULL;
}
As #WhozCraig points out, this is only one of the thread-related problems in your code.
Edit
As WhozCraig and user3386109 point out, the changes I suggest below introduce a race condition. I haven't encountered this exact use case (passing different values to different threads through a single variable), so I can't offer any useful advice; simply take the explanation for why the warnings occur as what they are.
Original
pthread_create(&tid, NULL, isPrime, (void *)num++);
The expression (void *)num++ attempts to convert the type of the expression num++ to void *; since integers and pointers may have different sizes and representations, this is potentially a bad idea.
Ideally, you should do something more like the following:
{
pthread_create( &tid, NULL, isPrime, (void *) &num );
num++;
}
Unfortunately, (void *) &num++ won't work; the result of the ++ operator isn't an lvalue, so you can't apply the & operator to it.
(void *) &num is converting from one pointer type to void *, which is safer than converting from an integer type to a pointer type.
Then, in the isprime function, you would need to make the corresponding change:
int num = *((int *)vargp);
That is, convert vargp back to a pointer to int and dereference it.
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 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'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'm getting a seg fault within this code, but I can't find the problem anywhere. It compiles just fine with -lpthread, but it just won't run. This program takes in an integer from the command line and then creates a new thread to calculate the collatz conjecture using that value. This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void print_con();
void calc_con(int *n);
int * values[1000];
int main(int argc, char * argv[])
{
int* num;
*num = 15;
pthread_t thread;
pthread_create(&thread,(pthread_attr_t*)NULL, (void *)&calc_con, (void *)num);
pthread_join(thread, NULL);
print_con();
return 0;
}
void calc_con(int *n)
{
int i = 0;
int * x;
*x = *n;
*values[0] = *x;
while(*x > 1)
{
if(*x % 2 == 0)
*x /= 2;
else if(*x % 2 == 1)
{
*x *= 3;
*x++;
}
i++;
*values[i] = *x;
}
pthread_exit(0);
}
void print_con()
{
int i;
for(i = 0; i < 1000; i++)
{
if(*values[i] > 0)
printf("%d", *values[i]);
}
}
okay you need to pass a void * as an argument to pthread_create, but you still need to respect the basics:
int* num;
*num = 15;
pthread_t thread;
pthread_create(&thread,(pthread_attr_t*)NULL, (void *)&calc_con, (void *)num);
Here *num = 15; you're writing 15 to an uninitialized pointer. That's undefined behaviour.
I would do:
int num = 15;
pthread_t thread;
pthread_create(&thread,(pthread_attr_t*)NULL, &calc_con, &num);
note that you don't have to cast to void * from pointers on non-void. Since num is declared in the main routine, you can pass a pointer on it to your threads safely.
note that as pointed by dasblinkenlight, you also have to fix the recieving end, in calc_con, which has the same issue:
int * x; // uninitialized pointer
*x = *n; // copy data "in the woods"
just dereference into a local variable and you have your value:
int x = *((int *)n);
and another one:
int * values[1000];
is an uninitialized array of integer pointers, not an array of integers like you're intending. It should be
int values[1000];
then
values[0] = x;
(it's not because there's a lot of * operators that it's good code)
You are passing an int to your thread using a void*. This will work on many platforms, but there is no guarantees that the number would "round-trip" correctly. Once you get pointer back, you save it in a dereferenced uninitialized pointer, which is incorrect.
Pass a pointer to num instead, and copy the pointer into x directly:
void calc_con(void *n);
...
void calc_con(void *n) {
int i = 0;
int * x = n;
*values[0] = *x;
while(*x > 1) {
if(*x % 2 == 0) {
*x /= 2;
} else if(*x % 2 == 1) {
*x *= 3;
*x++;
}
i++;
*values[i] = *x;
}
pthread_exit(0);
}
...
int num = 15;
pthread_create(&thread,(pthread_attr_t*)NULL, calc_con, (void *)&num);
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void* lsearch(int* key,int* base,int count,int elemSize){
int i = 0;
for(i = 0; i < count; i++){
void* elemAddr = (base + (i * elemSize));
if(memcmp(key,elemAddr,elemSize) == 0){
return elemAddr;
}
}
return NULL;
}
int main(){
int a[] = {10,20,30,40,50,60};
int key = a[2];
printf("\n sizeof(a) : %d \n",sizeof(a));
int size = sizeof(a)/sizeof(a[0]);
printf("\n size : %d \n",size);
int* search = lsearch(&key,a,size,sizeof(int));
printf("\n search : %d \n",*search);
return 0;
}
Getting a segmentation fault, dunno why the for loop is looping till the count and returns a NULL, since the key 30 is present in the array a[].
This doesn't do what you think it's doing:
void* elemAddr = (base + (i * elemSize));
The way pointer arithmetic works, adding a value to a pointer actually adds that value times the base datatype size to the pointer. You don't have to do it yourself. So this will do what you want:
void* elemAddr = base + i;
Actually, there's really no need to use memcmp here. You have an array of int and an int value to compare against, so just do that directly:
for(i = 0; i < count; i++){
if (*key == base[i]) {
return &base[i];
}
}
void* lsearch(int* key,int* base,int count,int elemSize){
int i = 0;
for(i = 0; i < count; i++){
void* elemAddr = (base + (i * elemSize));
The problem is how you are assigning elemAddr... you're compensating for the size of each element as well as the index, but you're dealing with int * data so standard pointer math already does this compensation for you; you therefore double compensate.
void* elemAddr = (base + i);
is what you want.
Alternatively you could change the type of base to be a void * which would require you to do the compensation you're already doing.