Thread: Circular character buffer with pthreads/mutex/cond deadlock help!

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

    Circular character buffer with pthreads/mutex/cond deadlock help!

    I am implementing a circular character buffer for an assignment, the requirements are pretty strict so I can't change the logic from what it is now too much. Unfortunately, this code deadlocks right out of the gate. I'm new to pthreads and concurrent programming in general so I could use some help spotting the error here.

    Code:
    #include <pthread.h>
    #include <stdio.h>
    
    #define QSIZE 10
    
    pthread_cond_t full,/* count == QSIZE */ 
    	       empty;/* count == 0 */ 
    pthread_mutex_t m; /* implements critical section */ 
    unsigned int iBuf, /* tail of circular queue */ 
    	     oBuf; /* head of circular queue */ 
    int count; /* count characters */ 
    char buf [QSIZE]; /* the circular queue */ 
    
    void Put(char s[]) {/* add "ch"; wait if full */
    	int size = sizeof(s)/sizeof(char);
    	printf("size: %d", size); //doesn't print
    	pthread_mutex_lock(&m); 
    	int i;
    	for(i = 0; i < size; i++) {
    		while (count >= QSIZE) 
    			pthread_cond_wait(&full, &m);/* is there empty slot? */ 
    	
    		buf[iBuf] = s[i]; /* store the character */ 
    		iBuf = (iBuf+1) % QSIZE; /* increment mod QSIZE */ 
    		count++; 
    		if (count == 1) 
    			pthread_cond_signal(&empty);/* new character available */ 
    	}
    	pthread_mutex_unlock(&m); 
    } 
    char Get() {/* remove "ch" from queue; wait if empty */ 
    	char ch; 
    
    	pthread_mutex_lock(&m); 
    	while (count <= 0) 
    		pthread_cond_wait(&empty, &m);/* is a character present? */ 
    
    	ch = buf[oBuf]; /* retrieve from the head of the queue */ 
    	oBuf = (oBuf+1) % QSIZE; 
    	count--; 
    	if (count == QSIZE-1) 
    		pthread_cond_signal(&full);/* signal existence of a slot */ 
    	
    	pthread_mutex_unlock(&m); 
    	return ch; 
    } 
    
    void * p1(void *arg) {
    	int i;
    	for (i = 0; i < 5; i++) {
    		Put("hella"); 
    	}
    }
    
    void * p2(void *arg) {
    	int i;
    	for (i = 0; i < 5; i++) {
    		Put("goodby"); 
    	}
    }
    
    int main() { 
    	pthread_t t1, t2;
    	void *r1, *r2;
    	oBuf = 0; iBuf = 0; count=0; /* all slots are empty */ 
    
    	pthread_cond_init(&full, NULL); 
    	pthread_cond_init(&empty, NULL); 
    	pthread_mutex_init(&m, NULL); 
    	
    	pthread_create(&t1, NULL, p1, &r1);
    	pthread_create(&t2, NULL, p2, &r2);
    	
    	printf("Main"); //doesn't print
    	char c;
    	int i = 0;
    	while (i < 55) {
    		c = Get();
    		printf("%c",c);
    		i++;
    	}
    
    	pthread_join(t1, &r1);
    	pthread_join(t2, &r2);
    	return 0; 
    }
    EDIT: I think i need to modify the reentry queue somehow, but I know nothing of how to do it.
    Last edited by wassat676; 06-26-2011 at 05:04 PM.

  2. #2
    Registered User
    Join Date
    May 2011
    Posts
    11
    ok I figured something out at least. I should have been using strlen in the Put method. Now it will print, almost in the correct order, but it still deadlocks at some point. Heres the new code:

    Code:
    #include <pthread.h>
    #include <stdio.h>
    #include <assert.h>
    #include <string.h>
    #define QSIZE 10
    
    pthread_cond_t full,/* count == QSIZE */ 
    	       empty,/* count == 0 */ 
    	       ready;
    pthread_mutex_t m, n; /* implements critical section */ 
    unsigned int iBuf, /* tail of circular queue */ 
    	     oBuf; /* head of circular queue */ 
    int count; /* count characters */ 
    char buf [QSIZE]; /* the circular queue */ 
    
    void Put(char s[]) {/* add "ch"; wait if full */
    	pthread_mutex_lock(&m); 
    	printf("putting %s\n", s);
    	int i;
    	for(i = 0; i < strlen(s); i++) {
    		while (count >= QSIZE) 
    			pthread_cond_wait(&full, &m);/* is there empty slot? */ 
    	
    		buf[iBuf] = s[i]; /* store the character */ 
    		iBuf = (iBuf+1) % QSIZE; /* increment mod QSIZE */ 
    		count++; 
    		if (count == 1) 
    			pthread_cond_signal(&empty);/* new character available */ 
    	}
    	pthread_mutex_unlock(&m); 
    } 
    char Get() {/* remove "ch" from queue; wait if empty */ 
    	char ch; 
    
    	pthread_mutex_lock(&m); 
    	while (count <= 0) 
    		pthread_cond_wait(&empty, &m);/* is a character present? */ 
    
    	ch = buf[oBuf]; /* retrieve from the head of the queue */ 
    	oBuf = (oBuf+1) % QSIZE; 
    	count--; 
    	if (count == QSIZE-1) 
    		pthread_cond_signal(&full);/* signal existence of a slot */ 
    	
    	pthread_mutex_unlock(&m); 
    	return ch; 
    } 
    
    void * p1(void *arg) {
    	int i;
    	for (i = 0; i < 5; i++) {
    		Put("hella");
    	}
    	pthread_exit((void *)99);
    }
    
    void * p2(void *arg) {
    	int i;
    	for (i = 0; i < 5; i++) {
    		Put("goodby");
    	}
    	pthread_exit((void *)21);
    }
    
    int main() { 
    	pthread_t t1, t2;
    	void *r1, *r2;
    	oBuf = 0; iBuf = 0; count=0; /* all slots are empty */ 
    
    	assert(pthread_cond_init(&full, NULL) == 0); 
    	assert(pthread_cond_init(&empty, NULL) == 0); 
    	assert(pthread_mutex_init(&m, NULL) == 0); 
    	
    	assert(pthread_create(&t1, NULL, p1, &r1) == 0);
    	assert(pthread_create(&t2, NULL, p2, &r2) == 0);
    	
    	char c;
    	int i = 0;
    	while (i < 55) {
    		c = Get();
    		printf("%c\n",c);
    		i++;
    	}
    
    	assert(pthread_join(t1, &r1) == 0);
    	assert(pthread_join(t2, &r2) == 0);
    	pthread_mutex_destroy(&m);
    	return 0; 
    }
    Something must still be screwy with the mutex or the monitors, please HELP!

  3. #3
    Registered User
    Join Date
    May 2011
    Posts
    11
    Oh, wassat676, heres your problem!

    You should add another mutex so that puts/gets aren't conflicting.

    Thanks me.

    EDIT: nvm, now its all deterministic and stuff. I still need help.

  4. #4
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> I should have been using strlen in the Put method.
    Yeah, "sizeof(s)" will always be the size of a pointer in that context.

    >> pthread_cond_t full,/* count == QSIZE */
    The way "full" is being used is a little bit confusing. The variable name typically indicates the program state being signaled or being waited on. eg:
    pthread_cond_signal(&full); // signal others that the Q is full
    pthread_cond_wait(&full, &m); // wait until the Q is full
    But this is just a code readability/maintainability issue.

    >> assert(pthread_cond_init(&full, NULL) == 0);
    assert() expressions are intended to only be executed in a debug build. So when NDEBUG is defined, all that code disappears. Instead, check the return code and call perror() followed by exit().

    The use of condition variables isn't quite right. Think ab
    When should Put block? * When the Q is full.
    When should Put un-block? * When the Q is not full (space is available).
    When should Get block? * When the Q is empty.
    When should Get un-block? * When the Q is not empty.
    When should a blocked Put be signaled? * When the Q is not full (space is available).
    When should a blocked Get be signaled? * When the Q is not empty.

    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 11-11-2010, 12:05 PM
  2. Mutex, Cond and Thread questions (pthread, linux)
    By thebearot in forum C Programming
    Replies: 14
    Last Post: 04-23-2010, 12:10 PM
  3. scanf issue - character in buffer
    By demps in forum C Programming
    Replies: 2
    Last Post: 01-19-2010, 07:51 PM
  4. Circular buffer - logic difficulty
    By erasm in forum C Programming
    Replies: 2
    Last Post: 10-05-2009, 01:08 PM
  5. Circular Buffer
    By parisframe in forum C Programming
    Replies: 11
    Last Post: 09-16-2009, 11:05 PM

Tags for this Thread