Reputation: 13
I have the problem, that when I want to assign my buffer array values, there is a segmentation fault Code:
#define BMPHEADER_SIZE 54
#include <pthread.h>
#include <stdio.h>
#include <sys/time.h>
// there will be a low level I/O function from the operating system
extern long write(int, const char *, unsigned long);
float zoom = 1.5;
float quadLimit = 3.0;
char colorLimit = 40;
pthread_mutex_t lock;
typedef struct Complex_s {
float re;
float im;
} Complex;
typedef struct {
int width;
int height;
int anfang;
int ende;
float imageRelation;
char *blueGreenRed;
//char *buffer;
char ***buffer;
}info1;
// bad, but fast !!!
int intFloor(double x) {
return (int)(x+100000) - 100000;
}
// count chars until \0 or space or "to long"
int len(char * str) {
int ddorf=0;
while (str[ddorf] != '\0' && str[ddorf] != ' ' && ddorf != 40225) ++ddorf;
return ddorf;
}
// read a positive number from a char array
int str2num(char * str) {
int result = 0;
int b = 1;
int l = len(str);
int i;
for(i=1; i<l; ++i) b *= 10;
for(i=0; i<l; ++i) {
result += b * (int)(str[i] - '0');
b /= 10;
}
return result;
}
void toRGB(int id, char * blueGreenRed) {
blueGreenRed[0] = 0;
blueGreenRed[1] = 0;
blueGreenRed[2] = 0;
if ( id == colorLimit ) return;
float hi,q,t,coeff;
coeff = 7.0 * (id/(float)colorLimit);
hi = intFloor(coeff);
t = coeff - hi;
q = 1 - t;
if (hi == 0.0) {
blueGreenRed[2] = 0;
blueGreenRed[1] = t*255; //immer mehr green und blau -> dunkelblau zu cyan
blueGreenRed[0] = t*127 + 128;
} else if (hi == 1.0) {
blueGreenRed[2] = t*255; //immer mehr rot -> cyan zu weiss
blueGreenRed[1] = 255;
blueGreenRed[0] = 255;
} else if (hi == 2.0) {
blueGreenRed[2] = 255;
blueGreenRed[1] = 255;
blueGreenRed[0] = q*255; // immer weniger blau -> weiss zu gelb
} else if (hi == 3.0) {
blueGreenRed[2] = 255;
blueGreenRed[1] = q*127 + 128; // immer weniger green -> gelb zu orange
blueGreenRed[0] = 0;
} else if (hi == 4.0) {
blueGreenRed[2] = q*127 + 128; // orange wird dunkler -> orange zu braun
blueGreenRed[1] = q*63 + 64;
blueGreenRed[0] = 0;
} else if (hi == 5.0) {
blueGreenRed[2] = 128;
blueGreenRed[1] = 64;
blueGreenRed[0] = t*128; // mehr blau -> braun zu violett
} else if (hi == 6.0) {
blueGreenRed[2] = q*128; // weniger rot und green -> violett wird dunkelblau
blueGreenRed[1] = q*64;
blueGreenRed[0] = 128;
}
}
char* calculatePunkt(int x, int y, int width, int height, float imageRelation, char *blueGreenRed) {
char iterate=0;
Complex c = {0,0};
Complex newz = {0,0};
Complex z = {0,0};
float quad=0;
c.re = zoom * (-1.0 + imageRelation * ( (x-1.0) / (width-1.0)) );
c.im = zoom * ( 0.5 - (y-1.0) / (height-1.0) );
// iterate
for ( iterate=1; iterate < colorLimit && quad < quadLimit; ++iterate ) {
quad = z.re * z.re + z.im * z.im;
newz.re = (z.re * z.re) - (z.im * z.im) + c.re;
newz.im = z.re * z.im * 2.0 + c.im;
z = newz;
}
toRGB(iterate, blueGreenRed);
return blueGreenRed;
}
void *calculateThread(void *arg){
info1 *abc =(info1*) arg;
int x, y;
int anfang = abc->anfang;
int ende = abc->ende;
int width = abc->width;
int height = abc->height;
float imageRelation = abc->imageRelation;
char *blueGreenRed = abc->blueGreenRed;
char ***buffer = abc->buffer;
//char *buffer = abc->buffer;
for (y=anfang; y <= ende; ++y) {
for (x=1; x <= width; ++x) {
char* rgb = calculatePunkt(x, y, width, height, imageRelation, blueGreenRed);
fprintf(stderr, "test, %d\n", anfang);
pthread_mutex_lock(&lock);
//buffer[(y-1)+(height*(x-1))+(height*width*0)] = rgb[0];
//buffer[(y-1)+(height*(x-1))+(height*width*1)] = rgb[1];
//buffer[(y-1)+(height*(x-1))+(height*width*2)] = rgb[2];
buffer[y-1][x-1][0] = 1;
buffer[y-1][x-1][1] = 1;
buffer[y-1][x-1][2] = 1;
pthread_mutex_unlock(&lock);
}
}
}
int main(int argc, char ** argv, char ** envp) {
int width = str2num(argv[1]);
int height = str2num(argv[2]);
int anzahl_threads = str2num(argv[3]);
float imageRelation = (float)width/(float)height;
int i, j, anfang, ende, y;
char blueGreenRed[3];
char buffer[height][width][3];
for(i=0; i<height; i++){
for(j=0; j<width; j++){
buffer[i][j][0]=0;
buffer[i][j][1]=0;
buffer[i][j][2]=0;
}
}
//char *buffer = malloc(height*width*3*sizeof(char));
//*buffer = (char*){ 0 };
unsigned char info[BMPHEADER_SIZE] = {
//size
'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0,
//width //height
40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0,
// datasize
0,0,0,0, 0,0,0,0
};
// BMP lines must be of lengths divisible by 4
char span[4] = "\0\0\0\0";
int spanBytes = 4 - ((width * 3) % 4);
if (spanBytes == 4) spanBytes = 0;
int psize = ((width * 3) + spanBytes) * height;
*( (int*) &info[2]) = BMPHEADER_SIZE + psize;
*( (int*) &info[18]) = width;
*( (int*) &info[22]) = height;
*( (int*) &info[34]) = psize;
write(1, (char *) info, BMPHEADER_SIZE);
struct timeval start, end;
gettimeofday(&start, 0);
int interval = height/anzahl_threads;
info1 *abc = malloc(anzahl_threads*sizeof(info1));;
pthread_t *thread = malloc(anzahl_threads*sizeof(pthread_t));
if(pthread_mutex_init(&lock, NULL)){
fprintf(stderr, "Error initializing mutex\n");
return 1;
}
for(i=0; i<anzahl_threads; i++){
(abc+i)->width = width;
(abc+i)->height = height;
(abc+i)->imageRelation = imageRelation;
(abc+i)->blueGreenRed = blueGreenRed;
(abc+i)->buffer = ***buffer;
//abc->buffer = *buffer;
anfang = 1+(i*interval);
(abc+i)->anfang = anfang;
if(i<(anzahl_threads-1)){
ende = (i*interval)+interval;
}
else{
ende = height;
}
(abc+i)->ende = ende;
if (pthread_create(&thread[i], NULL, calculateThread, (void*)(abc+i))) {
fprintf(stderr, "Error creating thread\n");
return 1;
}
}
for(i=0; i<anzahl_threads; i++){
if (pthread_join(thread[i], NULL)) {
fprintf(stderr, "Error joining thread\n");
return 2;
}
}
pthread_mutex_destroy(&lock);
for(y=1; y<=height; ++y){
// BMP lines must be of lengths divisible by 4
write(1, span, spanBytes);
}
write(1, buffer, height*width*3);
//free(buffer);
free(thread);
free(abc);
gettimeofday(&end, 0);
unsigned long timediff = ((end.tv_sec*1000000)+end.tv_usec) - ((start.tv_sec*1000000)+start.tv_usec);
fprintf(stderr, "Gesamtzeit in Mikrosek.: %lu\n", timediff);
return 0;
}
Valgrind:
==28366== Thread 2:
==28366== Invalid read of size 8
==28366== at 0x401115: calculateThread (in /home/nilskk/Schreibtisch/Betriebssysteme/Abgabe2/Aufgabe1/mandel1)
==28366== by 0x4E3F183: start_thread (pthread_create.c:312)
==28366== by 0x514F37C: clone (clone.S:111)
==28366== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==28366==
==28366==
==28366== Process terminating with default action of signal 11 (SIGSEGV)
==28366== Access not within mapped region at address 0x0
==28366== at 0x401115: calculateThread (in /home/nilskk/Schreibtisch/Betriebssysteme/Abgabe2/Aufgabe1/mandel1)
==28366== by 0x4E3F183: start_thread (pthread_create.c:312)
==28366== by 0x514F37C: clone (clone.S:111)
==28366== If you believe this happened as a result of a stack
==28366== overflow in your program's main thread (unlikely but
==28366== possible), you can try to increase the size of the
==28366== main thread stack using the --main-stacksize= flag.
==28366== The main thread stack size used in this run was 8388608.
--28366-- REDIR: 0x50d7d00 (libc.so.6:free) redirected to 0x4c2bd80 (free)
==28366==
==28366== HEAP SUMMARY:
==28366== in use at exit: 640 bytes in 4 blocks
==28366== total heap usage: 4 allocs, 0 frees, 640 bytes allocated
==28366==
==28366== Searching for pointers to 4 not-freed blocks
==28366== Checked 16,869,264 bytes
==28366==
==28366== Thread 1:
==28366== 544 bytes in 2 blocks are possibly lost in loss record 3 of 3
==28366== at 0x4C2CC70: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==28366== by 0x4012E14: allocate_dtv (dl-tls.c:296)
==28366== by 0x4012E14: _dl_allocate_tls (dl-tls.c:460)
==28366== by 0x4E3FD92: allocate_stack (allocatestack.c:589)
==28366== by 0x4E3FD92: pthread_create@@GLIBC_2.2.5 (pthread_create.c:500)
==28366== by 0x40187E: main (in /home/nilskk/Schreibtisch/Betriebssysteme/Abgabe2/Aufgabe1/mandel1)
==28366==
==28366== LEAK SUMMARY:
==28366== definitely lost: 0 bytes in 0 blocks
==28366== indirectly lost: 0 bytes in 0 blocks
==28366== possibly lost: 544 bytes in 2 blocks
==28366== still reachable: 96 bytes in 2 blocks
==28366== suppressed: 0 bytes in 0 blocks
==28366== Reachable blocks (those to which a pointer was found) are not shown.
==28366== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==28366==
==28366== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==28366==
==28366== 1 errors in context 1 of 2:
==28366== Thread 2:
==28366== Invalid read of size 8
==28366== at 0x401115: calculateThread (in /home/nilskk/Schreibtisch/Betriebssysteme/Abgabe2/Aufgabe1/mandel1)
==28366== by 0x4E3F183: start_thread (pthread_create.c:312)
==28366== by 0x514F37C: clone (clone.S:111)
==28366== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==28366==
==28366== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
When I comment the buffer assignment in the thread function, it works. So it has to do something with the buffer, but I don't see the mistake.
Upvotes: 0
Views: 884
Reputation: 17403
You are trying to access the data via a pointer to pointer to pointer to char
(char ***
), but the data is actually an array [height
] of array [width
] of array [3] of char
(char [height][width][3]
). A pointer to the first element of this array is a pointer to an array [width
] of array [3] of char
(char (*)[width][3]
). Since width
and height
are variable, the info1
type cannot contain a member buffer
of type char (*)[width][3]
, so the easiest thing to do is to declare it as a void *
:
typedef struct {
...
void *buffer;
...
} info1;
In function calculateThread
, the original width
value is available, so you can declare local variable buffer
with the correct type and initialize it:
char (*buffer)[width][3] = abc->buffer;
In function main
, the assignment (abc+i)->buffer = ***buffer;
is obviously incorrect as ***buffer
is of type char
. You want a pointer to the start of the buffer contents, which is just buffer
, so change that to:
(abc+i)->buffer = buffer;
Upvotes: 1
Reputation: 8142
This line of code is obviously wrong. The type on the left hand side is a char ***
and you're assigning to it a char
, with specifically the value of 0
as that is how you initialise buffer
at the top of main
(abc+i)->buffer = ***buffer;
ideally you want it to be
(abc+i)->buffer = buffer;
but that won't work as buffer
is a 3 dimensional array rather than a char ***
and they're not equivalent.
You could either create buffer
as a char ***
by allocating the various levels or since each thread is only accessing a subset of buffer
you could make it a global variable?
Upvotes: 1