Reputation: 1453
I am learning c and ncurses and wrote a simple snake game with halfdelay(1) to semi-automate it. When I added threads it stopped working in that I couldn't get any input from the keyboard.
So I wrote a short program to try threads/ncurses and mutex locking. The code has 2 threads with their own functions (fn and fn2). When I run it with the wmove/wprint in the respective function calls it works (well, it prints to screen!) I tried to implement mutex locking and moved the code to another function called print_to_screen() and nothing happens.
I have added if(thread_id == pthread_self())
to switch between threads but still nothing happens. I have added a couple of commented out lines which show the 2 threads reaching the print_to_screen() function, but the code in the if loops is not running at all.
Please help me, I am at my wits end - I even tried reading usr/inc.ncurses.h
and man was that ever unhelpful! Here is the code. If you comment out the wmove/wprint bits in the 2 functions and uncomment the print_to_screen() call you can see the difference. The ncurses setup is from the invisible-island tutorial, if anyone knows why he has put (void) in front of his ncurses calls please let me know. TIA for any help you can give.
#include <stdlib.h>
#include <curses.h>
#include <signal.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
void *myfunction(void *);
void *myfunction2(void *);
void print_to_screen(void);
static void finish(int);
pthread_t thread1, thread2;
pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER;
int thread1_id, thread2_id, count, count2;
int done;
int ch;
WINDOW *mywin;
int main(void){
(void) signal(SIGINT, finish); /* arrange interrupts to terminate */
(void) initscr(); /* initialize the curses library */
keypad(stdscr, TRUE); /* enable keyboard mapping */
(void) nonl(); /* tell curses not to do NL->CR/NL on output */
(void) cbreak(); /* take input chars one at a time, no wait for \n */
(void) echo(); /* echo input - in color */
if (has_colors())
{
start_color();
/*
* Simple color assignment, often all we need. Color pair 0 cannot
* be redefined. This example uses the same value for the color
* pair as for the foreground color, though of course that is not
* necessary:
*/
init_pair(1, COLOR_RED, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
init_pair(3, COLOR_YELLOW, COLOR_BLACK);
init_pair(4, COLOR_BLUE, COLOR_BLACK);
init_pair(5, COLOR_CYAN, COLOR_BLACK);
init_pair(6, COLOR_MAGENTA, COLOR_BLACK);
init_pair(7, COLOR_WHITE, COLOR_BLACK);
}
count = count2 = 0;
done = 0;
mywin = newwin(LINES, COLS, 0,0);
keypad(mywin, TRUE);
pthread_create( &thread1, NULL, myfunction, NULL);
pthread_create( &thread2, NULL, myfunction2, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
finish(0);
exit(0);
}
void *myfunction(void *ptr){
thread1_id = pthread_self();
halfdelay(-1);
while(1){
ch = getch();
if(ch == 'q') break;
wmove(mywin, 5,2);
wprintw(mywin, "Thread 1 at print");
wmove(mywin, 10,count);
waddch(mywin, ch);
wrefresh(mywin);
//print_to_screen();
if(count++ >70) count = 0;
nanosleep((struct timespec[]){{0, 250000000}}, NULL);
}
done = 1;
}
void *myfunction2(void *ptr){
thread2_id = pthread_self();
while(1){
if(done == 1) break;
if(count++ >24) count = 0;
wmove(mywin, 6,2);
wprintw(mywin, "Thread 2 at print");
wmove(mywin, count, 10);
wprintw(mywin, "hello from thread 2");
wrefresh(mywin);
//print_to_screen();
nanosleep((struct timespec[]){{0, 250000000}}, NULL);
}
}
void print_to_screen(){
pthread_mutex_lock(&mx);
//printw("PTHREAD ID = %d : ", pthread_self());
//printw("thread1_id = %d : thread2_id = %d\n", thread1_id, thread2_id);
if(pthread_self() == thread1_id){
wmove(mywin, 5,2);
wprintw(mywin, "Thread 1 at print");
wmove(mywin, 10,count);
waddch(mywin, ch);
wrefresh(mywin);
}
if(pthread_self() == thread2_id){
wmove(mywin, 6,2);
wprintw(mywin, "Thread 2 at print");
wmove(mywin, count, 10);
wprintw(mywin, "hello from thread 2");
wrefresh(mywin);
}
pthread_mutex_unlock(&mx);
}
static void finish(int sig)
{
endwin();
/* do your non-curses wrapup here */
}
Upvotes: 2
Views: 1741
Reputation: 70911
As a start:
int thread1_id, thread2_id, count, count2;
should be
int count, count2;
pthread_t thread1_id, thread2_id;
Also print_to_screen()
is never called.
Upvotes: 2