Thread: Semaphore noob - sem_open ok, but sem_init not

  1. #1
    Registered User
    Join Date
    May 2011
    Posts
    36

    Semaphore noob - sem_open ok, but sem_init not

    Hi, I'm learning Semaphores for a class and am wondering why sem_open is working for me, but sem_init (which was recommended in my text) leads to a segmentation fault when I run it. See below (the sem_init attempts are commented out so you can see exactly what I did). Thanks!

    Also a side question, how commonly are these types of semaphores used in the real world? It was kind of hard to find good info about them online (and my text is not very descriptive either). That kind of led me to believe maybe they weren't very widespread.

    Code:
    #include <stdio.h>
    #include <pthread.h>
    #include <assert.h>
    #include <semaphore.h>
    #include <fcntl.h>
    
    sem_t *ab, *ac, *ad, *bf, *ce, *de, *ef;
    
    void *pa(void *arg) {
    	printf("thread A start\n");
    	sleep(1);
    	printf("thread A end\n");
    	assert( sem_post(ab)==0 );
    	assert( sem_post(ac)==0 );
    	assert( sem_post(ad)==0 );
    	pthread_exit((void *)99);
    }
    
    void *pb(void *arg) {
    	assert( sem_wait(ab)==0 );
    	printf("thread B start\n");
    	sleep(1);
    	printf("thread B end\n");
    	assert( sem_post(bf)==0 );
    	pthread_exit((void *)99);
    }
    
    void *pc(void *arg) {
    	assert( sem_wait(ac)==0 );
    	printf("thread C start\n");
    	sleep(1);
    	printf("thread C end\n");
    	assert( sem_post(ce)==0 );
    	pthread_exit((void *)99);
    }
    
    void *pd(void *arg) {
    	assert( sem_wait(ad)==0 );
    	printf("thread D start\n");
    	sleep(1);
    	printf("thread D end\n");
    	assert( sem_post(de)==0 );
    	pthread_exit((void *)99);
    }
    
    void *pe(void *arg) {
    	assert( sem_wait(ce)==0 );
    	assert( sem_wait(de)==0 );
    	printf("thread E start\n");
    	sleep(1);
    	printf("thread E end\n");
    	assert( sem_post(ef)==0 );
    	pthread_exit((void *)99);
    }
    
    void *pf(void *arg) {
    	assert( sem_wait(bf)==0 );
    	assert( sem_wait(ef)==0 );
    	printf("thread F start\n");
    	sleep(1);
    	printf("thread F end\n");
    	pthread_exit((void *)99);
    }
    
    int main() {
    	pthread_t a, b, c, d, e, f;
    	void *r;
    	ab=sem_open("semab", O_CREAT, 0700, 0);
    	ac=sem_open("semac", O_CREAT, 0700, 0);
    	ad=sem_open("semad", O_CREAT, 0700, 0);
    	bf=sem_open("sembf", O_CREAT, 0700, 0);
    	ce=sem_open("semce", O_CREAT, 0700, 0);
    	de=sem_open("semde", O_CREAT, 0700, 0);
    	ef=sem_open("semef", O_CREAT, 0700, 0);
    	/*sem_init(ab,0,0);
    	sem_init(ac,0,0);
    	sem_init(ad,0,0);
    	sem_init(bf,0,0);
    	sem_init(ce,0,0);
    	sem_init(de,0,0);
    	sem_init(ef,0,0);*/
    	assert(pthread_create(&a, NULL, pa, (void *)99) == 0);
    	assert(pthread_create(&b, NULL, pb, (void *)99) == 0);
    	assert(pthread_create(&c, NULL, pc, (void *)99) == 0);
    	assert(pthread_create(&d, NULL, pd, (void *)99) == 0);
    	assert(pthread_create(&e, NULL, pe, (void *)99) == 0);
    	assert(pthread_create(&f, NULL, pf, (void *)99) == 0);
    	assert(pthread_join(a, &r) == 0);
    	assert(pthread_join(b, &r) == 0);
    	assert(pthread_join(c, &r) == 0);
    	assert(pthread_join(d, &r) == 0);
    	assert(pthread_join(e, &r) == 0);
    	assert(pthread_join(f, &r) == 0);
    	assert( sem_close(ab)==0 );
    	assert( sem_close(ac)==0 );
    	assert( sem_close(ad)==0 );
    	assert( sem_close(bf)==0 );
    	assert( sem_close(ce)==0 );
    	assert( sem_close(de)==0 );
    	assert( sem_close(ef)==0 );
    	return 0;
    }

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    You never actually test any of your return values to see if the functions you are calling have worked or not. For all you know, ab may be ... SEM_FAILED.


    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    I tried it with and without the sem_init calls in there, and it worked for me, no seg fault.

    You use an obscene amount of unnecessary asserts, and fail to check if sem_open succeeded, so you may be calling sem_init on invalid semaphores for some reason. Get rid of those nasty assert calls, and do some proper error checking (look at the man pages for each function to determine what it returns on success/fail), like:
    Code:
    ab = sem_open(...);
    if (ab == SEM_FAILED) {
        perror("sem_open failed for semaphone ab");
        return EXIT_FAILURE;
    }

  4. #4
    Registered User
    Join Date
    May 2011
    Posts
    36
    Quote Originally Posted by anduril462 View Post
    I tried it with and without the sem_init calls in there, and it worked for me, no seg fault.
    When you put the sem_init calls in, did you comment out the sem_open calls? That is what makes it fail for me.

    Quote Originally Posted by anduril462 View Post
    You use an obscene amount of unnecessary asserts, and fail to check if sem_open succeeded, so you may be calling sem_init on invalid semaphores for some reason. Get rid of those nasty assert calls, and do some proper error checking (look at the man pages for each function to determine what it returns on success/fail), like:
    Code:
    ab = sem_open(...);
    if (ab == SEM_FAILED) {
        perror("sem_open failed for semaphone ab");
        return EXIT_FAILURE;
    }
    Yeah, the assert thing was just a copy of a simpler semaphore example my professor made, I tried to extend it to a greater amount of threads changing as little as possible. I will look into the error checking you describe.

  5. #5
    Registered User
    Join Date
    May 2011
    Posts
    36
    Quote Originally Posted by quzah View Post
    You never actually test any of your return values to see if the functions you are calling have worked or not. For all you know, ab may be ... SEM_FAILED.


    Quzah.
    Why would it work (run) every single time with open and fail (not run) every single time with init?

  6. #6
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by The111 View Post
    Why would it work (run) every single time with open and fail (not run) every single time with init?
    I didn't run it, I was just observing your writing style. It's bad form, in my mind, to not pay attention to things that can fail.


    Quzah.
    Hope is the first step on the road to disappointment.

  7. #7
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    No, I didn't comment that stuff out, must've missed that.
    Code:
    sem_t *ab, *ac, *ad, *bf, *ce, *de, *ef;
    Uninitialized globals are set to 0 at program start up, so you have 7 NULL pointers. sem_open allocates memory for a sem_t object, so passing them to sem_init passes valid memory in. If you comment out sem_open, they no longer get set to the memory allocated by sem_open and are still NULL, so sem_init tries to do something with the sem_t object stored at address 0, thus the seg fault.

    Learn to use a debugger and you can step through line by line, and see exactly what's going on in a case like this.

  8. #8
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by The111 View Post
    When you put the sem_init calls in, did you comment out the sem_open calls? That is what makes it fail for me.
    The init function doesn't say it replaces the open function in the docs I scanned on it. I'm not sure why you would assume that.

    I think you are supposed to use sem_init this way:
    Code:
    sem_t s;
    sem_init( &s, 0, 0 );
    My guess is that it initializes a sem_t instance, not that it allocates a new one for you. I haven't used either function before, but one mentions named semaphores (_open) vs unnamed (_init). I assume there is a reason.


    Quzah.
    Last edited by quzah; 06-17-2011 at 09:09 PM.
    Hope is the first step on the road to disappointment.

  9. #9
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    No, it didn't, but the examples I found suggest you should declare an actual semaphore object (not a pointer to), and pass the address of that into sem_init, to initialize the "unnamed" semaphore. I took that to mean that it performs a function similar to open, but without the naming or allocation.

    POSIX semaphores
    sem_init()-Initialize Unnamed Semaphore

    @The111: I've never really used semaphores. I've used mutexes for the little bit of threading stuff I've done. Not sure if one is better than the other in any way.

  10. #10
    Registered User
    Join Date
    May 2011
    Posts
    36
    Quote Originally Posted by anduril462 View Post
    No, it didn't, but the examples I found suggest you should declare an actual semaphore object (not a pointer to), and pass the address of that into sem_init, to initialize the "unnamed" semaphore.
    Ah, I tried it that way and it works mostly.
    sem_t ab and sem_init(&ab)
    rather than
    sem_t *ab and sem_init(ab)

    I am new to the whole pointer thing since I learned Java just last month as my first language, and this class has thrown me into C with no good foundation. I had *assumed* from some other trials and errors that any place where *x and x were required, I could get away with using x and &x instead... since x is the address of *x.... and &x is the address of x. But obviously my assumption proved wrong.

    Thanks for the quick replies all.

    Quote Originally Posted by quzah View Post
    The init function doesn't say it replaces the open function in the docs I scanned on it. I'm not sure why you would assume that.

    I think you are supposed to use sem_init this way:
    Code:
    sem_t s;
    sem_init( &s, 0, 0 );
    Correct, that worked. Not sure why either, but hopefully after today I never think about semaphores again... seems like you guys don't much. ;-)

  11. #11
    Registered User
    Join Date
    May 2011
    Posts
    36
    Quote Originally Posted by anduril462 View Post
    (look at the man pages for each function to determine what it returns on success/fail)
    Which man pages do you mean?
    Thanks!

  12. #12
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by The111 View Post
    Correct, that worked. Not sure why either, but hopefully after today I never think about semaphores again... seems like you guys don't much. ;-)
    Your issue really isn't a semaphore issue. It's an issue with using an instance of an object vs using a pointer to an instance of an object. Consider:
    Code:
    void init_int( int *p )
    {
        *p = 10;
    }
    You had a function that did that. You used it like this:
    Code:
    int *anIntPtr;
    ...
    init_int( anIntPtr );
    Which didn't work, because anIntPtr isn't actually an integer, it is a pointer to an integer, that doesn't actually point to an integer. It just points some random place (or in your case NULL). So you crash when you try to dereference it.

    Instead, we said to do:
    Code:
    int anInt;
    init_int( &anInt );
    You could have just as well done this:
    Code:
    int *anIntPtr = malloc( sizeof *anIntPtr );
    if( anIntPtr )
        init_int( anIntPtr );
    Which is effectively what your _open function was doing for you (as best I can tell).

    So really it was a pointer issue, not a semaphore issue.

    Quote Originally Posted by The111 View Post
    Which man pages do you mean?
    See: Man page - Wikipedia, the free encyclopedia


    Quzah.
    Hope is the first step on the road to disappointment.

  13. #13
    Registered User
    Join Date
    May 2011
    Posts
    36
    Quote Originally Posted by quzah View Post
    So really it was a pointer issue, not a semaphore issue.
    Yes, I'm definitely on board with that. However, when I do it this way, and it works:

    Code:
    sem_t s;
    sem_init( &s, 0, 0 );
    How is "s" getting allocated? Probably a stupid question, like I said I am new to C and pointers. It seems like pointers (sem_t*) must be explicitly allocated with malloc, but not regular variables (sem_t). Not positive I understand.

    Quote Originally Posted by quzah View Post
    Ah, I knew about man for bash commands, but I was not aware it explained C functions as well. Cool, thanks.

  14. #14
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Whenever you declare a variable, that variable is allocated. So when you type
    Code:
    sem_t s;
    then voila, you have a sem_t. When you type
    Code:
    sem_t *s;
    then s is also allocated -- but s is only a pointer-to-sem_t, not a sem_t itself. If you want that pointer to point somewhere, you have to have a sem_t around for it to point to, or at the least a chunk of memory the right size (i.e., what you get from malloc).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 11-14-2010, 11:14 AM
  2. Porting Unix to windows: semaphores/sem_open
    By somekid413 in forum C Programming
    Replies: 1
    Last Post: 11-10-2010, 04:58 PM
  3. What's wrong with sem_init()?
    By jsrig88 in forum C Programming
    Replies: 3
    Last Post: 11-03-2009, 03:59 PM
  4. sem_init -> bus error
    By g_p in forum C Programming
    Replies: 4
    Last Post: 12-03-2006, 12:14 PM
  5. semaphore
    By laasunde in forum C Programming
    Replies: 0
    Last Post: 11-01-2002, 11:03 AM