Jump to content



Πέρασμα μεταβλητών σε thread function στη C


Thodoris21

Recommended Posts

Δημοσιεύτηκε

Καλησπέρα.Θέλω να περάσω μεταβλητές στην pthread_create η οποία καλεί μια συνάρτηση που εκτελεί κάθε thread.Το πρόβλημα είναι οτι μέσω της pthread_create δεν μπορώ να περάσω πάνω από μια μεταβλητές.Υπάρχει κάποιος τρόπος εκτός από την χρήση structs?

Ευχαριστώ.

Αν δεν κάνω λάθος περνάς το ορίσματα στην συνάρτηση που θα εκτελέσει το thread.

void *arg δεν μπορείς εκεί να περάσεις πίνακα με τα ορίσματα ή struct όπως είπες?προσοχή στις global μεταβλητές

Η pthread_create σου δίνει την δυνατότητα να περάσεις ένα όρισμα ή έναν δείκτη σε μια struct.Δοκίμασα με struct αλλά κάποια ορίσματα παίζουν και άλλα χτυπάνε.Επίσης δεν μπορώ πως περνάω πίνακες στην struct.Γενικά έχω πρόβλημα με τις μεταβλητές.

pthread_create(3): create new thread - Linux man page

στον κώδικα του παραδείγματος



- δομή για ορίσματα που θα περάσεις στην συνάρτηση που θα εκτελει το thread

struct thread_info { /* Used as argument to thread_start() */
pthread_t thread_id; /* ID returned by pthread_create() */
int thread_num; /* Application-defined thread # */
char *argv_string; /* From command-line argument */
};

- συνάρτηση που θα εκτελέσει το thread

static void *thread_start(void *arg)
{
struct thread_info *tinfo = (struct thread_info *) arg;
char *uargv, *p;

printf("Thread %d: top of stack near %p; argv_string=%s\n",
tinfo->thread_num, &p, tinfo->argv_string);

uargv = strdup(tinfo->argv_string);
if (uargv == NULL)
handle_error("strdup");

for (p = uargv; *p != '\0'; p++)
*p = toupper(*p);

return uargv;
}

- δημιουργία threads (προσοχη στο πως καλείται η pthread_create)

s = pthread_create(&tinfo[tnum].thread_id, &attr,&thread_start, &tinfo[tnum]);

Κατι αντιστοιχο εχω κανει αλλα χτυπαει το προγραμμα.Βασικα εχω φτιαξει το σεριακο προγραμμα και πρεπει να το μετατρεψω σε παραλληλο χρησιμοποιωντας posix threads.Θα ποσταρα τον κωδικα αλλα ειναι 300 γραμμες!

struct thread_info *tinfo = (struct thread_info *) arg;

Σημαντικότατο cast στον κώδικα της thread_start

Το ίδιο έχω κάνει και εγώ...


void *maps(void *arguments) {
struct arg_struct *args = arguments;
......

Κάποιες παραμέτρους μπορώ να τις περάσω μέσω της struct αλλά έχω πρόβλημα με το πέρασμα των πινάκων!

Όχι δεν κάνεις το ίδιο :S

implicit cast

void *maps(void *arguments) {

struct arg_struct *args = arguments;

......

explicit cast

struct arg_struct *args = (struct arg_struct *) arguments;

Στο πρώτο λες στον compiler να κάνει την μετατροπή όσο καλύτερα μπορεί.Στην δεύτερη του λες συγκεριμένα σε τι τυπο θα κάνει την μετατροπή.

πίνακες σαν members ενός struct

struct thread_info { /* Used as argument to thread_start() */

char name[64];

char course[128];

int age;

int year;

};

υποθέτω αυτό δουλεύει σαν αρχικοποίηση

thread_info.name = {(64 στοιχεία χωρισμένα με κόμμα)}

Ναι αλλα επελεξα το πρωτο γιατι το προγραμμα ετρεχε.Με τον δευτερο τροπο που προτεινεις δεν επερνα λαθη στο compile αλλα segmantation fault στην εκτελεση!

Καταρχήν ο pointer από τα δεδομένα που περνάς πρέπει να δείχνει μια θέση μνήμης στο heap memory space. Οπότε θα πρέπει να κάνεις allocation είτε με global μεταβλητές, είτε σε κάποιο static pointer.

Δεύτερων, αν η μνήμη αυτή είναι κοινή για όλα τα threads τότε χρησιμοποιείς semaphores και mutexes όταν θες να έχεις πρόσβαση σε αυτή, αλλιώς θα πρέπει να έχεις κάποιο array πχ που το κάθε thread θα χρησιμοποιεί indexed μνήμη από αυτό. Και οι δυο προσεγγίσεις έχουν τα θετικά τους και τα αρνητικά τους, όσων αφορά την ταχύτητα εκτέλεσης και την πολυπλοκότητα.

Τέλος το casting είναι πάντα απαραίτητο και μόνο ορισμένες φορές που θέλεις να κάνεις κάποια συγκεκριμένα κόλπα παίζεις με αυτό. Στο υπόλοιπο 99.99% των περιπτώσεων θα πρέπει να είναι όπως το λέει ο nucleus.

Το segmentation fault έχει να κάνει με άλλο λάθος στον κώδικά σου και ότι με το casting. Μήπως η μνήμη που δείχνει ο Pointer που περνάς δείχνει στο stack...? Αν συμβαίνει αυτό, τότε είναι λογικό να παίρνεις segmentation fault, γιατί το thread πάει να κάνει προσπέλαση σε mem space που δεν υπάρχει...

Δεν μπορώ να καταλάβω γιατί παίρνω segmentation fault σε αυτό το πρόγραμμα...


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <pthread.h>

#define PI 3.14159265
int dim;
int threads;

void *maps(void *id) {

int thread_id = *((int*)id);
int from = (dim/threads*thread_id);
int to = (dim/threads*thread_id)+dim/threads;

printf("Map dimensions %dx%d\n",dim,dim);
}


int main (int argc, char *argv[]) {
int i;
dim=atoi(argv[1]);
threads=atoi(argv[2]);
pthread_t tid[threads];

for (i = 0; i < threads; i++) {
pthread_create(&tid[i], NULL, &maps,&i);
}

for (i = 0; i < threads; i++) {
pthread_join(tid[i], NULL);
}


return 0;
}

Οκ το εφτιαξα.Το θεμα ειναι οτι εχω ορισεις καποιους πινακες με malloc.Μπορω να τους κανω global?

Αν τα threads απλώς διαβάζουν τιμές από τους πίνακες και δεν τις αλλάζουν ναι μπορείς να τους κάνεις global.Aν τις αλλάζουν θέλει συγχρονισμό πχ για να μην γράφουν 2 threads στην ίδια θέση.

Οχι τα threads αλλαζουν τιμες των πινακων.Οποτε πρεπει να χρησιμοποιήσω mutexes σωστά?Το θεμα ειναι πως γινεται η global δηλωση των πινακων?

Όπως κάθε global μεταβλητή.Το θέμα είναι να γίνει σωστα το synchronization με mutexes ή σημαφόρους.

Τα thread χρησιμοποιούν τις αλλαγμένες τιμές των πινάκων ή όχι?

Τα threads γεμιζουν τους πινακες με καποιες τιμες και η main() τις τυπωνει.Έκανα μια αλλαγη και μεχρι στιγμης παιζει.


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <pthread.h>

#define PI 3.14159265
struct timeval StartTime, EndTime;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int dim;
int threads;
int** prevkMap;
int** nextkMap;
float** prevtempMap;
float** preveMap;
float** nexttempMap;
float** nexteMap;

void *maps(void *id) {
srand(time(NULL));
int thread_id = *((int*)id);
int from = (dim/threads*thread_id);
int to = (dim/threads*thread_id)+dim/threads;
int step,i,j,num;

for (step=from; step<to; step++) {
pthread_mutex_lock(&mutex);
for (i=0; i<dim; i++) {
for (j=0; j<dim; j++) {
num=rand() % 6; //τυχαίος αριμός μεταξύ 0 και 5
prevkMap[i][j]=num;//πέρασμα τιμής στον πίνακα
prevtempMap[i][j]=22;
preveMap[i][j]=0;
}

}
pthread_mutex_unlock(&mutex);
}

}


int main (int argc, char *argv[]) {
int i,j;
dim=atoi(argv[1]);
threads=atoi(argv[2]);
pthread_t tid[threads];
prevkMap = malloc(dim * sizeof(int*));
nextkMap = malloc(dim * sizeof(int*));
prevtempMap = malloc(dim * sizeof(int*));
preveMap = malloc(dim * sizeof(int*));
nexttempMap = malloc(dim * sizeof(int*));
nexteMap = malloc(dim * sizeof(int*));

for (i = 0; i < dim; i++)
{
prevkMap[i] = malloc(dim * sizeof(int));
nextkMap[i] = malloc(dim * sizeof(int));
prevtempMap[i] = malloc(dim * sizeof(int));
nexttempMap[i] = malloc(dim * sizeof(int));
preveMap[i] = malloc(dim * sizeof(int));
nexteMap[i] = malloc(dim * sizeof(int));
}

gettimeofday(&StartTime, NULL);
for (i = 0; i < threads; i++) {
pthread_create(&tid[i], NULL, &maps,&i);
}

for (i = 0; i < threads; i++) {
pthread_join(tid[i], NULL);
}
gettimeofday(&EndTime, NULL);

printf("\n");
if (EndTime.tv_usec < StartTime.tv_usec) {
int nsec = (StartTime.tv_usec - EndTime.tv_usec) / 1000000 + 1;
StartTime.tv_usec -= 1000000 * nsec;
StartTime.tv_sec += nsec;
}
if (EndTime.tv_usec - StartTime.tv_usec > 1000000) {
int nsec = (EndTime.tv_usec - StartTime.tv_usec) / 1000000;
StartTime.tv_usec += 1000000 * nsec;
StartTime.tv_sec -= nsec;
}
//Εκτύπωση χρόνου σε δευτερόλεπτα
printf("\n\nCalculation time: %ld.%.6ld seconds\n", EndTime.tv_sec - StartTime.tv_sec, EndTime.tv_usec - StartTime.tv_usec);

free (prevkMap);
free (nextkMap);
free (prevtempMap);
free (nexttempMap);
free (preveMap);
free (nexteMap);

return 0;
}

Το κομματι του συγχρονισμου ειναι σωστο?

for (step=from; step<to; step++) {   
pthread_mutex_lock(&mutex);
for (i=0; i<dim; i++) {
for (j=0; j<dim; j++) {
num=rand() % 6; //τυχαίος αριμός μεταξύ 0 και 5
prevkMap[i][j]=num;//πέρασμα τιμής στον πίνακα
prevtempMap[i][j]=22;
preveMap[i][j]=0;
}

}
pthread_mutex_unlock(&mutex);
}

Δεν ξέρω αν πρέπει να μπει και το for στο critical section δηλαδή να γίνει

pthread_mutex_lock(&mutex);
for (step=from; step<to; step++) {
for (i=0; i<dim; i++) {
for (j=0; j<dim; j++) {
num=rand() % 6; //τυχαίος αριμός μεταξύ 0 και 5
prevkMap[i][j]=num;//πέρασμα τιμής στον πίνακα
prevtempMap[i][j]=22;
preveMap[i][j]=0;
}

}
}
pthread_mutex_unlock(&mutex);

Το πρωτο for οριζει τι κομματι θα παρει καθε thread.Τα επομενα δυο for ειναι για το γεμισμα των πινακων.Εχω την εντυπωση οτι εφοσον το καθε thread παιρνει το δικο του κομματι,δεν εχει νοημα η χρηση των mutexes!Ειναι περιττο και καθυστερει και τον κωδικα νομιζω...

Αφου δουλεύει δεν το πειράζεις."Τοπικές" μεταβλητές είναι δεν θα πρέπει να έχουν πρόβλημα.

Το θεμα τωρα ειναι οτι οι τιμες των πινακων γραφονται σε αρχεια.Υπαρχει τροπος να ορισω τα file descriptors σαν global μεταβλητες?

Για παραδειγμα εχω:

FILE * map[24];

Θελω να το ορισω σαν global μεταβλητη με χρηση της malloc για να ειναι ορατο και απο την συναρτηση των threads.

Archived

This topic is now archived and is closed to further replies.

×
×
  • Δημιουργία...

Important Information

Ο ιστότοπος theLab.gr χρησιμοποιεί cookies για να διασφαλίσει την καλύτερη εμπειρία σας κατά την περιήγηση. Μπορείτε να προσαρμόσετε τις ρυθμίσεις των cookies σας , διαφορετικά θα υποθέσουμε ότι είστε εντάξει για να συνεχίσετε.