Jump to content



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


Thodoris21

Recommended Posts

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

Ευχαριστώ.

Link to comment
Share on other sites

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

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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]);

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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


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

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

Link to comment
Share on other sites

Όχι δεν κάνεις το ίδιο :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 στοιχεία χωρισμένα με κόμμα)}

Link to comment
Share on other sites

Καταρχήν ο 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 που δεν υπάρχει...

Link to comment
Share on other sites

Δεν μπορώ να καταλάβω γιατί παίρνω 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;
}

Link to comment
Share on other sites

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

Link to comment
Share on other sites

Τα 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;
}

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

Link to comment
Share on other sites

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);

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

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

FILE * map[24];

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

Link to comment
Share on other sites

Archived

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

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

Important Information

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