This code carefully avoids the workers trampling on each others toes by ensuring they are made to work on disjoint ranges in the memory-mapped file. Because the file is memory mapped, all that's needed to swap the pixels around is to read and write them from the memory.
This code carefully avoids the workers trampling on each others toes by ensuring they are made to work on disjoint ranges in the memory-mapped file. Because the file is memory mapped, all that's needed to swap the pixels around is to read and write them from the memory. This is a single source file.
All the functions except main() are static because they are not referenced outside this file. Your original code had functions declared in the header that were not used outside their source file. You should avoid doing that - limit the amount of shared information to that which is essential.
Left to my own devices, I'd probably define the static functions before they are used, leaving main() at the bottom of the file. This avoids repeating the function declarations. I've left main() at the top and put all the function declarations before it, though some of them are actually redundant.
I've also created and extensively used two error reporting functions - err_error() and err_syserr() - which I use to do in one line what you repeatedly did in three. I get bored writing error handling code if I don't have those functions around. I also used a few assertions - and left them in.
I changed the number of workers to 7 to ensure that the row-range calculations are correct even when the total number of rows is not divisible by the number of workers. Overall, this is a good deal simpler than the original code; the GIMP seems to confirm that it is working correctly. I had some off-by-one errors in the line handling that it spotted; there could be some off-by-one errors in handling the ends of lines which it doesn't show because there is a white border all around the sketch.
If your homework must use semaphores, then this won't suit you - but...it actually would provide a good basis from which to do the semaphore work. You'd write a function to get the next line to be processed; it would use one semaphore to protect its data. Each worker would simply call that function to get the next line it should process.
However, synchronizing multiple processes is much easier if you don't have to do anything - and here, there is no need to do more than ensure that the processes do not interfere with each other. //############# MMF_INVERTER. C #include #include #include #include #include #include #include #include #include #include #include #include #define NUM_WORKERS 7 typedef struct pixel_t { uint8_t red; uint8_t green; uint8_t blue; } pixel_t; // PPM file header.
Typedef struct header_t { uint32_t width; uint32_t height; uint32_t depth; } header_t; #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) static const char *arg0 = 0; static size_t row_finish(size_t total, size_t parts, size_t index); static size_t row_start(size_t total, size_t parts, size_t index); static uint32_t readNextHeaderValue(FILE *fp); static void err_error(const char *format, ...); static void err_syserr(const char *format, ...); static void file_copy(FILE *in, FILE *out); static void getImageHeader(FILE *fp, header_t *hp); static void readType(FILE *fp); static void worker(size_t width, size_t row_lo, size_t row_hi, pixel_t *data); int main(int argc, char *argv) { int fdout; size_t i; struct stat sbuf; header_t h; uint8_t *data; pixel_t *data2; int last_index; pid_t pid; arg0 = argv0; if (argc 0 && total > 0 && parts 0 && total > 0 && parts 0) { if (fwrite(buffer, sizeof(char), nbytes, out)! = nbytes) err_syserr("Failed to write to output file"); } } #define READ_BUFFER_LEN 16 static void readType(FILE *fp) { char bufREAD_BUFFER_LEN; if (fgets(buf, READ_BUFFER_LEN, fp) == NULL) err_syserr("Failed to read file"); if (strcmp(buf, "P6\n")! = 0) err_error("Invalid file type %.
*s found (should be P6)", (int)strlen(buf)-1, buf); } static uint32_t readNextHeaderValue(FILE *fp) { char bufREAD_BUFFER_LEN; uint32_t value; if (fgets(buf, READ_BUFFER_LEN, fp) == NULL) err_syserr("Failed to read file"); if (sscanf(buf, "%" SCNu32, &value)! = 1) err_syserr("Failed to convert %s to an integer", buf); return value; } static void getImageHeader(FILE *fp, header_t *hp) { assert(fp! = 0 && hp!
= 0); readType(fp); hp->width = readNextHeaderValue(fp); hp->height = readNextHeaderValue(fp); hp->depth = readNextHeaderValue(fp); if (hp->depth! = 255 || hp->width == 0 || hp->height == 0) err_error("Invalid value(s) read: width %zu, height %zu, depth %zu", hp->width, hp->height, hp->depth); }.
Thanks a lot for your answer, but yes, I really do need to use semaphores and those 4. The goal is to use semaphores, shared memory and/or memory mapped files. I just wanted my code to have no children alive, because it's working.It's far from perfect, I know, but all the functions were provided to the students, I just did the shared memory, semaphores and mmap part.
– neverMind Nov 25 '10 at 10:20 @NeverMind: I thought maybe that was the case. Well, you'll should use the memory mapped I/O as shown, and not the shared memory because that's redundant. You should still simply copy the original image to the result file and then manipulate the result file.
You should still create a single semaphore, and provide a single function that tells the workers which line (or a series of lines) to process; it could hand out up to 10 lines per call, say, unless there's nothing to do. The cleanup phase should be more or less as shown: simply wait for the kids to die; there is no need to go killing them. – Jonathan Leffler Nov 25 '10 at 15:17.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.