LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-24-2008, 02:45 PM   #1
fortenbt
LQ Newbie
 
Registered: Apr 2008
Posts: 4

Rep: Reputation: 0
Arrow Two threads somehow using the same data (seg fault with pthreads in c)


I have a (fairly large) program that encodes a bitmap image to a compressed format. My goal is to thread this program to encode multiple bitmap images to multiple compressed images. All the variables are "standalone," meaning I should only have to tell each thread, "Input file name is..., output file name is..., go..." then wait with a pthread_join at the end of my main.

The code works as non-threaded, and also works with one thread. My current test is on two threads. Most times I get a segmentation fault. Looking at the call stack using gdb, it happens at various places throughout the program. Sometimes (once or twice), it's gone all the way through and completed both threads successfully. When I looked at the output files, however, they were the same. Both threads compressed the same image. I don't understand how they are both using the same data, as each thread gets a different file name and should open a different image, using different variables to hold that data, etc. etc.

Does anyone have any idea what might be causing this? I'm assuming the seg faults are caused by the threads switching back and forth and somehow writing/reading some data that the other thread was writing/reading, but they should be operating on completely separate data. I'm fairly new to Linux threads, but have used Windows threads a decent amount.

Thanks for any help...the code I'm using to create the threads and their start routine is below.

Code:
int main()
{
    int i;
    pthread_t thread1;
    pthread_t thread2;

    char ** args1;
    char ** args2;
    for(i = 0; i < 2; i++)
    {
        args1 = calloc(1, sizeof(char)*MAX_STRING);
        args2 = calloc(1, sizeof(char)*MAX_STRING);
    }

    args1[0] = "tile0_0.bmp";
    args1[1] = "tile0_0.jp2";

    args2[0] = "tile0_1.bmp";
    args2[1] = "tile0_1.jp2";

    if( pthread_create( &thread1,
                        NULL, //NULL = default attr
                        start_routine,
                        (void)*args1 ) != 0 )
    {
        printf("error creating thread1\n");
    }

    if( pthread_create( &thread2,
                        NULL,
                        start_routine,
                        (void)*args2 ) != 0 )
    {
        printf("error creating thread2\n");
    }
...
}

static void * start_routine(void * arg)
{
    char ** myargs = (char **)arg;
    char * filename = (char*)calloc(1, sizeof(char)*64);
    char * outfilename = (char*)calloc(1, sizeof(char)*64);

    filename = myargs[0];
    outfilename = myargs[1];

    printf("myargs[0] (filename): %s\n", myargs[0]);
    printf("myargs[1] (outfile): %s\n", myargs[1]);

....
}
 
Old 04-24-2008, 04:06 PM   #2
jailbait
LQ Guru
 
Registered: Feb 2003
Location: Virginia, USA
Distribution: Debian 12
Posts: 8,336

Rep: Reputation: 548Reputation: 548Reputation: 548Reputation: 548Reputation: 548Reputation: 548
I think that your problem is with the myargs array. I think that you have to create a new copy of myargs with malloc or calloc each time that you enter start_routine. Initialize each new copy of myargs from arg as you are doing now.

Free the myargs memory each time you exit start_routine or you will be creating a memory leak. You also should free the args1 and args2 memory when the corresponding thread finishes to avoid memory leaks. Memory leaks are a trivial problem in this code but when you generalize the code they could become significant.

------------------
Steve Stites
 
Old 04-24-2008, 06:31 PM   #3
fortenbt
LQ Newbie
 
Registered: Apr 2008
Posts: 4

Original Poster
Rep: Reputation: 0
Now that you pointed it out, that makes a lot of sense. Thanks for the advice. Hopefully this is the reason for the seg faults as well. The machine I have the code on is at work, so I'll get back tomorrow and let you know if that worked.

About the memory leaks, I am freeing the malloc/calloc'd variables, but didn't show that code.

Last edited by fortenbt; 04-24-2008 at 06:33 PM.
 
Old 04-25-2008, 10:15 AM   #4
fortenbt
LQ Newbie
 
Registered: Apr 2008
Posts: 4

Original Poster
Rep: Reputation: 0
I noticed that I was allocating memory in a for loop without even using the control variable, and I wasn't allocating space to the char** before mallocing in that for loop. So I fixed that, added the malloc to myargs, and reran the program. I seem to be able to complete successfully more often, but I still get seg faults most of the time.

Here's another weird one: one of the times it completed successfully, it compressed the same image. Another time, it compressed both images, but tile0_0.bmp was compressed to tile0_1.jp2, and tile0_1.bmp used tile0_0.jp2 as the output.

Updated code below.

Code:
int main()
{
    int i;
    pthread_t thread1;
    pthread_t thread2;

    char ** args1 = calloc(1, sizeof(char*)*2);
    char ** args2 = calloc(1, sizeof(char*)*2);
    for(i = 0; i < 2; i++)
    {
        args1[i] = calloc(1, sizeof(char)*MAX_STRING);
        args2[i] = calloc(1, sizeof(char)*MAX_STRING);
    }

    args1[0] = "tile0_0.bmp";
    args1[1] = "tile0_0.jp2";

    args2[0] = "tile0_1.bmp";
    args2[1] = "tile0_1.jp2";

    if( pthread_create( &thread1,
                        NULL, //NULL = default attr
                        start_routine,
                        (void)*args1 ) != 0 )
    {
        printf("error creating thread1\n");
    }

    if( pthread_create( &thread2,
                        NULL,
                        start_routine,
                        (void)*args2 ) != 0 )
    {
        printf("error creating thread2\n");
    }
...
    for(i = 0; i < 2; i++)
    {
        free(args1[i]);
        free(args2[i]);
    }
    free(args1);
    free(args2);

    return 0;
}

static void * start_routine(void * arg)
{
    int i;
    char ** myargs = calloc(1, sizeof(char*)*2);
    for(i = 0; i < 2; i++)
    {
        myargs[i] = calloc(1, sizeof(char)*MAX_STRING);
    }
    myargs = (char **)arg;
    char * filename = (char*)calloc(1, sizeof(char)*64);
    char * outfilename = (char*)calloc(1, sizeof(char)*64);

    filename = myargs[0];
    outfilename = myargs[1];

    printf("myargs[0] (filename): %s\n", myargs[0]);
    printf("myargs[1] (outfile): %s\n", myargs[1]);

....
    for(i = 0; i < 2; i++)
    {
        free(myargs1[i]);
    }
    free(myargs);
}
 
Old 04-25-2008, 10:52 AM   #5
fantas
Member
 
Registered: Jun 2007
Location: Bavaria
Distribution: slackware, xubuntu
Posts: 143

Rep: Reputation: 22
I guess the main problem here is that you allocate char memory, and then initialize them with string literals (basically overwriting the pointers of the newly allocated stuff with other pointers) and then freeing the literals (which the system takes care of), resulting in memory errors.

In short, for literals you don't need to allocate extra memory (needless to say no need to free it afterwards).

Try it like that (untested, changes surrounded by #####):

Code:
int main()
{
    int i;
    pthread_t thread1;
    pthread_t thread2;

    char ** args1 = calloc(1, sizeof(char*)*2);
    char ** args2 = calloc(1, sizeof(char*)*2);
    #####
    /*for(i = 0; i < 2; i++)
    {
        args1[i] = calloc(1, sizeof(char)*MAX_STRING);
        args2[i] = calloc(1, sizeof(char)*MAX_STRING);
    }*/
    #####

    args1[0] = "tile0_0.bmp";
    args1[1] = "tile0_0.jp2";

    args2[0] = "tile0_1.bmp";
    args2[1] = "tile0_1.jp2";

    if( pthread_create( &thread1,
                        NULL, //NULL = default attr
                        start_routine,
                        (void)*args1 ) != 0 )
    {
        printf("error creating thread1\n");
    }

    if( pthread_create( &thread2,
                        NULL,
                        start_routine,
                        (void)*args2 ) != 0 )
    {
        printf("error creating thread2\n");
    }
...
    #####
    /*for(i = 0; i < 2; i++)
    {
        free(args1[i]);
        free(args2[i]);
    }*/
    #####
    free(args1);
    free(args2);

    return 0;
}

static void * start_routine(void * arg)
{
    #####
    /*int i;
    char ** myargs = calloc(1, sizeof(char*)*2);
    for(i = 0; i < 2; i++)
    {
        myargs[i] = calloc(1, sizeof(char)*MAX_STRING);
    }
    myargs = (char **)arg;
    char * filename = (char*)calloc(1, sizeof(char)*64);
    char * outfilename = (char*)calloc(1, sizeof(char)*64);

    filename = myargs[0];
    outfilename = myargs[1];*/
    

    char ** myargs = (char **)arg;

    char * filename = myargs[0];
    char * outfilename = myargs[1];
    #####

    printf("myargs[0] (filename): %s\n", myargs[0]);
    printf("myargs[1] (outfile): %s\n", myargs[1]);

....
    #####
    /*for(i = 0; i < 2; i++)
    {
        free(myargs1[i]);
    }*/
    #####
    free(myargs);
}
 
Old 04-25-2008, 11:22 AM   #6
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Code:
args1[0] = strdup("tile0_0.bmp");
ta0kira
 
Old 04-25-2008, 11:36 AM   #7
fortenbt
LQ Newbie
 
Registered: Apr 2008
Posts: 4

Original Poster
Rep: Reputation: 0
Tried fantas' and ta0kira's suggestions, but I'm still getting the same issue. I really don't think the issue is in the assignment of the strings, because for the multiple ways I've assigned them, they print out correctly as each thread starts up.

I was talking with a few other people, and the only thing we could come up with that was possibly the problem is that the threads are allocating memory in the same place as they're switching back and forth. Are malloc and calloc thread safe? Is it possible for one thread to begin to allocate, go to sleep, the other thread to allocate its space, go to sleep, and then the first thread allocates over portions of the second thread's space?

We figured that this could cause the seg faults and could explain the program encoding opposite images.

Thanks for your help
 
Old 04-25-2008, 12:18 PM   #8
fantas
Member
 
Registered: Jun 2007
Location: Bavaria
Distribution: slackware, xubuntu
Posts: 143

Rep: Reputation: 22
I oversaw something in my edited code: The last "free(myargs);" needs to go as well (i.e. as in comment it out, in the second last line), as it would lead to double freeing of the same memory (originally allocated by the main thread).
Otherwise the code looks OK-ish, assuming that the parts that were left out with a "..." are OK too.
 
Old 04-25-2008, 12:33 PM   #9
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
What's this all about?
Code:
(void)*args1
That doesn't look safe, or even like something that should compile. Try this:
Code:
(void*) args1
ta0kira
 
Old 04-25-2008, 12:34 PM   #10
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by fortenbt View Post
Tried fantas' and ta0kira's suggestions, but I'm still getting the same issue. I really don't think the issue is in the assignment of the strings, because for the multiple ways I've assigned them, they print out correctly as each thread starts up.
Without using dynamic allocation (i.e. duplicating the string literals,) this is just a coincidence.
ta0kira
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
seg fault vm_devadas Linux - Enterprise 1 12-05-2006 02:28 PM
is there any way to sleep threads using pthreads.... gajaykrishnan Programming 2 03-26-2005 02:20 PM
C seg fault drigz Programming 5 10-01-2004 03:35 PM
enable pthreads? (posix threads) cpluspaul Slackware 5 06-29-2004 05:56 AM
pthreads and segmentation fault 41JokerNAM Programming 3 03-27-2004 03:35 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 08:50 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration