I can't understand why if I use
while (tab[i+1] == 0)
{
i+=1;
}
My program hangs
but if I use
while (tab[++i] == 0);
It executes as it should. What am I missing?
Full code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <limits.h>
#define SIZE 100
typedef struct
{
unsigned int prime;
unsigned int size;
unsigned int *tab;
} shared_data;
void *sieve(void *);
sem_t mutex;
int main()
{
pthread_t tid;
unsigned int tab[SIZE];
sem_init(&mutex, 0, 0);
for (unsigned int i = 0; i < SIZE; i++)
{
tab[i] = i;
}
unsigned int i = 2; //index startowy
shared_data shared = {i, SIZE, tab};
while (i < SIZE)
{
shared.prime = tab[i];
pthread_create(&tid, NULL, sieve, &shared);
sem_wait(&mutex);
while (tab[++i] == 0);
}
pthread_join(tid, NULL); // czekaj az ostatni watek zakonczy dzialanie
sem_destroy(&mutex);
printf("Liczby pierwsze:\n");
for (unsigned int i = 0; i < SIZE; i++)
if (tab[i]) //pomin 0 przy wyswietlaniu
printf("%d | ", tab[i]);
printf("\n");
return 0;
}
void *sieve(void *arg_p)
{
shared_data arg = *(shared_data *)arg_p;
shared_data io = arg;
int unlock_thread = 1;
for (unsigned int i = io.prime + 1; i < io.size; i++)
{
if (io.tab[i] % io.prime == 0)
io.tab[i] = 0;
else if (unlock_thread)
{
sem_post(&mutex);
unlock_thread = 0;
}
}
if (unlock_thread)
sem_post(&mutex);
return NULL;
}
while (tab[i+1] == 0)
{
i+=1;
}
Checks the next element of tab and doesn't change i when it is zero.
This means i won't change to the value where tab[i] becomes zero.
In the other hand,
while (tab[++i] == 0);
First go to the next element of tab and therefore i can be changed to make tab[i] zero.
To separate access to tab and update of i, you can do like this:
do {
i+=1;
} while (tab[i] == 0);
Also note that you must not access (no read nor write) out-of-range elements of arrays. The array tab has only SIZE elements, so the available indices are only 0 to SIZE-1. This means you must not read tab[SIZE]. You should add range check to the loops like this:
while (++i < SIZE && tab[i] == 0);
do {
i+=1;
} while (i < SIZE && tab[i] == 0);
Related
I wrote a basic example of a threaded application which doesn't seem to be working as I expect it to work. The program should print the numbers from 0 to 99 but seems to be skipping. I've tracked it down to the fact that after the thread_join() loop executes for the first time, the next time, the info[k].tid is zero. I don't know why this happens though.
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct {
pthread_t tid;
int i;
int res;
} thread_info;
void *square(void *data) {
thread_info *info = (thread_info*) data;
info->res = info->i;
return NULL;
}
int main(void) {
int nthread = 2;
int lim = 100;
int *results;
results = calloc(lim, sizeof(int ));
thread_info *info = calloc(nthread, sizeof(thread_info));
for (int i=0; i<lim; i++) {
info[i % nthread].i = i;
pthread_create(&info[i].tid, NULL, square, info + (i%nthread));
if (((i+1) % nthread)) {
continue;
}
for (int k=0; k<nthread; k++) {
pthread_join(info[k].tid, NULL);
}
for (int k=0; k<nthread; k++) {
results[info[k].i] = info[k].res;
}
memset(info, 0, sizeof(thread_info) * nthread);
}
for (int i=0; i<100; i++) {
printf("%d\n", results[i]);
}
return 0;
}
The code as written is broken: here
for (int i=0; i<lim; i++) {
info[i % nthread].i = i;
pthread_create(&info[i].tid, NULL, square, info + (i%nthread));
...
you are accessing info[i].tid (with i in range [0, 100), but info only contains 2 (nthread) elements. That's a buffer overflow.
Here:
for (int k=0; k<nthread; k++) {
pthread_join(info[k].tid, NULL);
}
you are joining info[0].tid and info[1].tid. That works for i == 0 and i == 1, but fails for i == 3 due to the bug above.
You want:
for (int i=0; i<lim; i++) {
const int slot = i % nthread;
info[slot].i = i;
pthread_create(&info[slot].tid, NULL, square, info + slot);
You should also always check return value for all pthread_* functions. Doing so will save you a lot of debugging time.
For example, with this change the problem becomes clearer:
for (int k=0; k<nthread; k++) {
int rc = pthread_join(info[k].tid, NULL);
if (rc != 0) {
fprintf(stderr, "pthread_join: %s\n", strerror(rc));
abort();
}
}
...
gcc -g -pthread thr.c && ./a.out
pthread_join: No such process
Aborted
This is a multi-threaded program that outputs prime numbers. The user runs the program and enters a number into the command line. It creates a separate thread that outputs all the prime numbers less than or equal to the number entered by the user.
I have an error: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] I'm so close but I've been staring at this for awhile now. I thought I would get some feedback.
How can I fix this? It is referring to the void here:
(void *)count);
Here is all the code:
#include <stdio.h>
#include <pthread.h>
int N = 100; //number of promes to be generated
int prime_arr[100000] = {0}; //prime arrray
void *printprime(void *ptr) //thread function
{
int j, flag;
int i = (int)(long long int)ptr; //getting thread number
//for thread 0, we check for all primes 0,4,8,12
//for thread 1, we check for all primes 1,5,9,13
while (i < N) { //while number in range
flag = 0; //check if i has factor
for (j = 2; j <= i / 2; j++) //factor can be at max i/2 value
{
if (i % j == 0) //factor found
{
flag = 1;
break;
}
}
if (flag == 0 && (i > 1)) //prime found, no factor
{
prime_arr[i] = 1;
}
i += 4; //increase by interval of 4
}
}
int main()
{
printf("Enter N: ");
scanf("%d", &N); //input N
pthread_t tid[4] = {0}; //create an array of 4 threads
int count = 0;
for (count = 0; count < 4; count++) //initialize threads and start
{
printf("\r\n CREATING THREADS %d", count);
pthread_create(&tid[count], NULL, printprime,(void *)count); //count is passed as argument, target = printprime
}
printf("\n");
for (count = 0; count < 4; count++)
{
pthread_join(tid[count], NULL); //while all thread havent finished
}
int c = 0;
for (count = 0; count < N; count++) //print primes
if (prime_arr[count] == 1)
printf("%d ", count);
printf("\n");
return 0;
}
Here you cast count to a void* which isn't a compatible type.
pthread_create(&tid[count], NULL, printprime, (void*) count);
And here you try to convert it back to an int improperly:
int i = (int)(long long int)ptr;
I suggest creating workpackages, tasks that you instead use and cast proberly to void* and back.
Example:
#include <pthread.h>
#include <stdio.h>
typedef struct {
pthread_t tid;
int count;
} task_t;
void *printprime(void *ptr) {
task_t *task = ptr;
task->count += 10; // do some work
return NULL;
}
#define TASKS (4)
int main() {
task_t tasks[TASKS] = {0}; // an array of tasks
for (int count = 0; count < TASKS; ++count) {
tasks[count].count = count; // fill the task with some job
pthread_create(&tasks[count].tid, NULL, printprime, &tasks[count]);
}
// join and take care of result from all threads
for (int count = 0; count < TASKS; ++count) {
pthread_join(tasks[count].tid, NULL);
printf("task %d value = %d\n", count, tasks[count].count);
}
}
Demo
Use a uintptr_t or a intptr_t instead of an int.
Technically, that's for storing a pointer in an integer, not for storing an integer in a pointer. So it's not exactly kosher. But it's still a common practice.
To do it properly, you would need to (statically or dynamically) allocate a variable for each thread, and pass the address of that variable to the thread.
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 am getting the error variable sized object may not be initialized and I don't understand why.
Could someone show me how to fix this line?
int arr[size] = (int *)(augs->one);
Here is my code:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>
int count = 0;
int cmpfunc(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}
struct structure {
int two;
int *one;
};
void *sort(void *augments) {
struct structure *augs = (struct structure*)augments;
int i = 0;
int size = 1;
size = augs->two;
int arr[size] = (int *)(augs->one);
//int *arr = (int *)data;
//printf("sizeof:%d\n", sizeof(arr));
qsort(arr, size, sizeof(int), cmpfunc);
printf("finaloutput:\n");
for (i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return NULL;
}
int main(int argc, char *argv[]) {
FILE *myFile;
myFile = fopen("data.txt", "r");
// number of lines in file
char charicter;
for (charicter = getc(myFile); charicter != EOF; charicter = getc(myFile)) {
if (charicter == '\n') {
count++;
}
}
printf("count is %d\n", count);
int numberArray[count];
int i = 0;
if ((myFile = fopen("data.txt", "r"))) {
while ((fscanf(myFile, "%d", &numberArray[i]) != EOF)) {
++i;
}
fclose(myFile);
}
assert(argv[1] != NULL);
int num = atoi(argv[1]); //num equals number input
int arrayarray[num - 1][(count / num)];
int idx;
for (i = 0; i < (count); i++) {
printf("numberarray[%d]= %d\n", i, numberArray[i] /*[0],numberArray[i][1]*/);
}
for (i = 1; i < num + 1; i++) {
for (idx = 0; idx < (count / num); idx++) {
arrayarray[i - 1][idx] = numberArray[i * idx];
}
}
///*
for (i = 0; i < ((count / num)); i++) {
printf("arrayarray[0]=%d\n", arrayarray[0][i]);
}
//*/
int lastarray[((count / num) + (count % num))];
for (idx = 0; idx < ((count / num) + (count % num)); idx++) {
lastarray[idx] = numberArray[idx + ((count / num) * (num - 1))];
}
for (i = 0; i < ((((count / num) + (count % num)))); i++) {
printf("lastaray[%d]=%d\n", i, lastarray[i]);
}
//*******************
pthread_t thread_id_arr[num];
for (i = 0; i < num; i++) {
pthread_t tid;
struct structure *augs;
if (i != (num - 1)) {
augs = malloc(sizeof(struct structure) + sizeof(int) + sizeof(int) * num);
(*augs).one = arrayarray[i];
(*augs).two = (count / num);
pthread_create(&tid, NULL, sort, augs);
} else {
(*augs).one = lastarray;
(*augs).two = (count / num) + (count % num);
pthread_create(&tid, NULL, sort, augs);
//pthread_create(&tid, NULL, sort, (void*)lastarray);
}
thread_id_arr[i] = tid;
}
for (i = 0; i < num; i++) {
pthread_join(thread_id_arr[i], NULL);
}
return 0;
}
As others pointed out, you can't initialize a Variable Length Array with a pointer, like you are doing. However, you don't actually need a VLA at all. Use this instead :
int *arr = augs -> one;
You want to act directly on the array that is passed into the thread, not make a copy of it.
That being said, I see another problem. In the loop that spawns the sorting threads, you are not allocating a new args on the last loop iteration, it reuses the allocated args from the previous iteration, which can cause disaster for the 2nd-to-last thread. You need to move the malloc() call above the if.
Also, the malloc() is allocating more memory than your threads actually use. You only need to allocate enough memory for just the struct by itself, not for any integers following the struct.
Also, when each thread is done using the allocated args that it is given, it needs to free() the args to avoid leaking memory.
For this program I pass in numbers through the command line and then have a multithreaded program that takes each argument, calculates its factors, then prints them. I know c++, but I'm rough with c and can't seem to get the casting down correctly for this program. Specifically when I pass the argument into the thread_create and cast it to an integer. The code I have below compiles, but the value after the cast is always a 0. How do I cast the char value to a void* then to an integer?
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#define MAX_ARRAY (17)
void *thread_func(void *);
int factors[MAX_ARRAY];
int main(int argc, char *argv[]) {
pthread_t thread_handle[argc];
int i;
int g;
// Create Children Threads
for ( i = 0; i < argc; i++ ) {
pthread_create(&thread_handle[i], NULL, thread_func, &argv[i + 1]);
}
// Rejoin Threads
for ( i = 0; i < argc; i++ ) {
pthread_join(thread_handle[i], NULL);
// Print Factors Here
printf("%d: ", atoi(argv[i]));
for ( g = 0; g < MAX_ARRAY; g++ ) {
printf("%d, ", factors[g]);
}
printf("\n");
for ( g = 0; g < MAX_ARRAY; g++ ) {
factors[g] = 0;
}
}
return 0;
}
void *thread_func(void *data) {
int n = atoi(data);
int x;
int v;
printf("Number to factor is: %d\n", n);
for ( x = 1; x <= n; ++x ) {
if (n%x == 0)
factors[v++] = x;
}
return NULL;
}
The problem is that each thread uses the same array for the factors, without any synchronization. But if each thread had to get a lock for the array before running, they would in effect all run in sequence which would defeat the purpose of threading.
Incidentally, argv[0] is the program name, which you should skip.
What you should do is have a different factor array for each thread, so that they can work independently without interference. You should also do all the display in the main thread, to control the order in which things are printed.
Since it is probably best to display the factors in order, you should first create all the threads, then join all of them, then finally display the results.
There were also a few small errors here and there like off by one errors or uninitialized variables.
Here is a corrected version:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define MAX_ARRAY 17
typedef struct {
int factors[MAX_ARRAY];
int n;
} thread_data;
void * thread_func (void *);
int main (int argc, char *argv[]) {
int n = argc - 1;
pthread_t thread_handle[n];
thread_data thread_data_table[n];
int i;
// Create Children Threads
for (i = 0; i < n; i++ ) {
thread_data_table[i].n = atoi (argv[i + 1]);
pthread_create(&thread_handle[i], NULL, thread_func,
&thread_data_table[i]);
}
// Join Threads
for (i = 0; i < n; i++ ) {
pthread_join(thread_handle[i], NULL);
}
// Print Factors
for (i = 0; i < n; i++) {
int j;
printf("%d: ", thread_data_table[i].n);
for (j = 0; j < MAX_ARRAY; j++ ) {
int x = thread_data_table[i].factors[j];
if (x == 0) {
break;
}
printf("%d, ", x);
}
printf("\n");
}
return 0;
}
void * thread_func (void *data)
{
thread_data *p = (thread_data*)data;
int i;
int count = 0;
for (i = 1; i <= p->n; ++i ) {
if (p->n % i == 0) {
if (count == MAX_ARRAY) {
break;
}
p->factors[count++] = i;
}
}
if (count < MAX_ARRAY) {
p->factors[count] = 0;
}
return NULL;
}