ABA


"תהליכים בשפת C בסביבת לינוקס"
גירסת הדפסה        
קבוצות דיון פיתוח, תיכנות ובניית אתרים נושא #7095 מנהל    סגן המנהל    מפקח   Winner    צל"ש   מומחה  
אשכול מספר 7095
chenke 
חבר מתאריך 1.7.02
730 הודעות
   14:39   04.10.03   
אל הפורום  
  תהליכים בשפת C בסביבת לינוקס  
 
   כתבתי תוכנית שהמטרה שלה למיין קובץ טקסט ע"י מספר תהליכים במקביל באופן הבא: כל תהליך קורא מספר שורות מהקובץ לתוך מערך,שולח את המערך לפונקציה שממיינת אותו וכותב את תוכן המערך לקובץ משלו. לאחר שכל התהליכים מסיימים לרוץ, התוכנית הראשית ממזגת את כל הקבצים שנוצרו לקובץ אחד ממויין.

זה בתאוריה מה שהתוכנית אמורה לעשות, בפועל כל תהליך מסיים לעבוד אחרי שהוא חזר מהפונקציה שממיינת ולפני שהספיק לכתוב את תוכן המערך לקובץ.

מי שמכיר תהליכים בשפת C בסביבת לינוקס ויכול לעזור אשמח אם יגיב,

חן.


                                שתף        
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד

  האשכול     מחבר     תאריך כתיבה     מספר  
  תעלה את הקוד, נראה מה אפשר ליעץ. dryice 04.10.03 17:22 1
     בסדר להלן הקוד chenke  04.10.03 17:59 2
         הבעיה שבא אתה נתקל היא הקטנה שבבעיותך dryice 05.10.03 01:38 3
             אפשר קבל מספר עצות כדי לתקן את המעוות? chenke  05.10.03 09:03 4
                 כן, הוצאת הwait מחוץ ללואה שיוצרת תהליכים dryice 05.10.03 09:56 5
                     אז זה טוב או לא שהראש הקורא משותף? chenke  05.10.03 18:11 6

       
dryice

   17:22   04.10.03   
אל הפורום  
  1. תעלה את הקוד, נראה מה אפשר ליעץ.  
בתגובה להודעה מספר 0
 
  


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
chenke 
חבר מתאריך 1.7.02
730 הודעות
   17:59   04.10.03   
אל הפורום  
  2. בסדר להלן הקוד  
בתגובה להודעה מספר 1
 
   עבר עריכה לאחרונה בתאריך 05.10.03 בשעה 01:41 על ידי על-ידי dryice (מנהל הפורום)
 
מקווה שמהוא יוכל לעזור. (ד.א. את קטע הקוד למיזוג הקבצים שהתהליכים אמורים ליצור עוד לא כתבתי).
מצטער שלא צירפתי את הקוד בקובץ, אבל העלה קובץ לא עובד אצלי.

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#define ERROR_CODE -2

void error_exit(char *err_str,int ret_code);
void sort(char*input[],int i);
int main(int argc,char *argv[])
{

FILE *child_file;
FILE *fp;
char line[300],*my_pid_str,*my_file_name,buffer[10];
char* lines[100];
int i=0,not_empty,k,t1;
pid_t pid,my_pid; /*processid */
int status; /*returnedstatusvar */

size_t t;
if((fp=fopen(argv[1],"r"))!=NULL)
{
while(!feof(fp))
{

fgets(line,300,fp);
not_empty=0;
for(t=0;t<strlen(line);t++)
if(line[t]!=' ')not_empty=1;
if(not_empty&&line!="\n"&&line!="\t"&&line!="") i++;

// lines[i]=strdup(line);

}
}
k=i/100;
rewind(fp);
printf("number of process to be create is %d\n",k);
for(t=1;t<=k;t++)
{
if((pid=fork())<0)
error_exit("Fork error",-1);

/*if the fork returns 0- it's a child process*/
else if(pid==0){
i=0;
printf("a child is running\n");
while(i<100 && !feof(fp))
{

fgets(line,300,fp);
not_empty=0;
for(t1=0;t1<strlen(line);t1++)
if(line[t1]!=' ') not_empty=1;
if(not_empty&&line!="\n"&&line!="\t"&&line!="")

{
lines[i]=strdup(line);

i++;
}
}
printf("calling sort\n");
sort(lines,i);
printf("return from sort\n");
my_pid=getpid();
printf("proces pid %d\n",my_pid);
//strcpy(my_file_name,"");
sprintf(my_file_name,"%d.dat",my_pid);
printf("file name of the child is %s\n",my_file_name);
if((child_file=fopen(my_file_name,"w"))!=NULL)
{
for(t1=0;t1<i;t1++)
fprintf(child_file,"%s\n",lines[t1]);

fclose(child_file);
}
else printf("error open child file");
printf("the child proses is die\n");
exit(0);
}
if((pid=waitpid(pid,&status,0))<0)
error_exit("Error during waitpid",ERROR_CODE);
}
}
void error_exit(char *err_str,int ret_code)
{
perror(err_str);
exit(ret_code);
}

void sort(char *input[],int i)
{
int change=1,t;
char temp[300];
while(change)
{
change=0;
for(t=0;t<i-2;t++)
if (strcmp(input[t],input[t+1])>0)
{
//printf("%d\n",t);
strcpy(temp,input[t]);
//printf("temp=%s",temp);
input[t]=(char*)malloc(strlen(input[t+1])+1);
strcpy(input[t],input[t+1]);
//printf("input[t]=%s",input[t]);
input[t+1]=(char*)malloc(strlen(temp)+1);
strcpy(input[t+1],temp);
//printf("input[t+1]=%s\n",input[t]);
change=1;
}
}
}

תודה מראש,

חן
נערך לתיקון סוגריים מרובעות


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
dryice

   01:38   05.10.03   
אל הפורום  
  3. הבעיה שבא אתה נתקל היא הקטנה שבבעיותך  
בתגובה להודעה מספר 2
 
   אתה נתקל בכך שsprintf לא עובד שכן לא מוקצה
זכרון עבור my_file_name.

יש לך כמה בעיות חמורות יותר:
בראש ובראשונה התוכנית שלך לא מקבילית! אתה עושה fork
ומחכה לבן ושוב fork ושוב מחכה לבן, בשום שלב אין שני
תהליכי בן רצים בו זמנית, ולמעשה משום שfgets זאת ממש לא
פעולה אטומית המקבול הוא בכלל לא טריוויאלי.

עמו כן הצורה שבה אתה בודק האם שורה היא ריקה, היא שגויה
אתה עושה השוואה רדודה, איפה שחיוני להשוות תוכן.

וכמובן יש לי הערות סגנוניות רבות:
אינדנציה, משתנים ללא שימוש, חסר return, וכמובן שילוב הערות
בסגנון C++.

מן הסתם יש פה עוד צרות שלא שמתי לב אליהם במבט זריז.

DRYICE
נ.ב
סוגריים מרובעות אפשר לכתוב בפורום ע"י צירוף &l-;
ו&r-; ללא ה-.
יש כלי שממיר את הקוד כראוי:
http://rotter.net/transform.html


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
chenke 
חבר מתאריך 1.7.02
730 הודעות
   09:03   05.10.03   
אל הפורום  
  4. אפשר קבל מספר עצות כדי לתקן את המעוות?  
בתגובה להודעה מספר 3
 
   ערכתי לאחרונה בתאריך 05.10.03 בשעה 09:14 בברכה, chenke
 
יש לי גרסה של הקוד שבה פעולת ה- wait היא מחוץ ללואה שיוצרת את
התהליכים, האם זה הופך את הקוד למקבילי?
לגבי ה- sprintf, אני אנסה להקצות זיכרון ולראות אם זה יעזור.
אה ואני מצרף את הנוסח המקורי של השאלה:

התוכנית תבצע סימולציה של מיון מקבילי על מספר מעבדים. הסימולציה תתבצע באמצעות ריבוי תהליכים אשר יחקו מעבדים אמיתיים. התוכנית תקבל בתור פרמטר את שם הקובץ המכיל שורות תווים בסדר אקראי ותיצור מספר תהליכים כאשר כל תהליך מבצע מיון לקסיקוגרפי של חלק מהשורות של הקובץ. כל אחד מהתהליכים ישמור את התוצאה בקובץ זמני. לאחר שכל תהליכי הבן סיימו את ריצתם, תהליך האב יבצע מיזוג (merge) של התוצאות. בסוף ריצת התוכנית יודפס המיון הלקסיקוגרפי של השורות ל stdout.



הנחיות נוספות
1) קבצים זמניים שנוצרים ע"י תהליכי הבנים יקראו בשם x.dat כאשר x הינו ה process ID
של תהליך הבן המתאים.
2) התוכנית תיצור מספר תהליכי בנים וכל אחד מהם יקבל למיין 100 שורות מהקובץ הנועד למיון. הבן האחרון יכול לקבל פחות מ 100 שורות.
3) שורות התווים בקובץ המקורי יכולות להכיל תווים עם קוד ASCII בתחום 32-126 (תחום זה כולל גם את תו ה"רווח").
4) האורך המירבי של השורה בקובץ הנתון למיון יהיה 300 תווים.
5) גודל הקובץ שנועד למיון מוגבל רק ע"י מערכת ההפעלה.
6) התוכנית צריכה לאפשר מקביליות מירבית (מקביליות מדומה כמובן).
7) אם הקובץ שנועד למיון מכיל שורות שמורכבות מרווחים בלבד יש להתעלם מהן.
8) יש למספר את השורות הממוינות (ראה ריצה של פיתרון ביה"ס).

טיפול בשגיאות
א) שימו לב: תמיד יש לבדוק את הערכים המוחזרים ע"י קריאות המערכת. אם השגיאה קרתה בעקבות כישלונה של קריאת מערכת כלשהי, יש להשתמש ב- perror לצורך הדפסת ההודעה ולצאת עם סטטוס 1.
ב) אינכם חייבים (אך אפשר) לבצע בדיקת תקינות של הקלט כגון האם כל התווים הם בתחום שהוגדר או האם כל שורה בקובץ המיועד למיון היא באורך 300 תווים לכל היותר. אך יחד עם זאת התוכנית שלכם לא צריכה "ליפול" אם היא מקבלת קלט לא חוקי (הפלט כמובן יכול להיות שגוי במקרה זה).

תודה מראש,

חן.


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
dryice

   09:56   05.10.03   
אל הפורום  
  5. כן, הוצאת הwait מחוץ ללואה שיוצרת תהליכים  
בתגובה להודעה מספר 4
 
   ולעשות לולאה נפרדת בה מחכים לכל הבנים יהפוך למקבילי.

במחשבה שנייה על fgets זה שהיא לא אטומית לא מפריעה,
אבל מה שמאוד מפריעה זה שהמציין של איפה אתה נמצא בקובץ
לא משותף. כל תהליך חייב לדלג למקום בקובץ שבו הוא אמור להתחיל,
כל תהליך יודע איזה מהתהליכים הוא(מונה הלולאה היוצרת תהליכים)
ואז הוא צריך לדלג על 100 * מספר זה שורות, ורק אז לקרוא את
השורות שהוא צריך למיין.

אם הראש הקורא היה משותף (והוא לא) הייתה בעיה יותר קשה של
סינכרון.

DRYICE


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
chenke 
חבר מתאריך 1.7.02
730 הודעות
   18:11   05.10.03   
אל הפורום  
  6. אז זה טוב או לא שהראש הקורא משותף?  
בתגובה להודעה מספר 5
 
   הרעיון שלי הוא שאני חושב שהראש הקורא הוא כן משותף ולכן תהליך מסויים מתחיל לקרוא מהקובץ, ואז המתזמן מפסיק אותו בשלב מסויים ונותן את הזכות לתהליך אחר שממשיך לקרוא מהמקום שהתהליך הקודם הפסיק לקרוא וכך הלאה לגבי שאר התהליכים.

ד.א. הקצאת הזיכרון לפקודת ה- sprintf אכן פתרה את הבעייה שתהליכים מתים בטרם עת, אך מעיון בקבצים שנוצרים גיליתי בעייה חדשה, והיא: מספר השורות בקבצים שנוצרים איננו שווה ל- 100, אלא גדול מזה. אם תוכל למצוא את הסיבה אשמח.


תודה מראש,

חן


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד

תגובה מהירה  למכתב מספר: 
 
___________________________________________________________________

___________________________________________________________________
למנהלים:  נעל | תייק בארכיון | מחק | העבר לפורום אחר | מחק תגובות | עגן אשכול
       



© כל הזכויות שמורות ל-רוטר.נט בע"מ rotter.net