关于用curses库多线程编程遇到的莫名其妙的问题。

最近在看《unix/linux编程实践教程》,其中第十四章有一段代码,内容是任意输入一些字符串,每一个字符串由一个线程控制让它在终端以随机速度左右移动,主线程接收键盘字符0-9,来控制相应字符串移动方向。空格用来改变所有字符串运动方向。测试是在centos7的tty上进行的,当快速敲击键盘按键时,总是在终端某些位置出现莫名其妙的字符串,控制光标的函数在调用时已经上锁,初始化终端时调用了cbreak()和noecho(),想请教大牛为什么会出现终端显示莫名其妙字符的现象。代码如下(该代码做了一些修改,与书上源码不完全相同)。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<curses.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include<time.h>
#include<errno.h>
#include<fcntl.h>

#define MAXMSG 12       /* limit to number of strings   */
#define COLS 100
#define LINES 37
#define TUNIT 5000      /* timeunits in microseconds */
#define MSGLEN (COLS-2)

struct  propset {
        char    *str;                /* the message */
        int row;                   /* the row     */
        int delay;              /* delay in time units */
        volatile int    dir;      /* +1 or -1   */
        pthread_mutex_t myMutex;
    };

typedef struct str_attribute
{
    char ** avPtr;
    int num;
}StrAttribute;

static pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER;
static int num_msg;
static struct propset props[MAXMSG];    /* properties of string */

int setup(int nstrings, char *strings[], struct propset props[])
{
    int fd=open("/dev/tty",O_RDONLY);
    if(-1==dup2(fd,STDIN_FILENO))
        {
            perror(NULL);
            exit(EXIT_FAILURE);
        }

    close(fd);  

    num_msg=nstrings;
    int i;

    srand((unsigned int)time(NULL));
    for(i=0 ; i<num_msg; i++){
        props[i].str = strings[i];  
        props[i].row = i;       
        props[i].delay = 1+(rand()%15); 
        props[i].dir = ((rand()%2)?1:-1);   
        pthread_mutex_init(&props[i].myMutex,NULL); 
    }

    initscr();
    cbreak();
    noecho();
    clear();
    mvprintw(LINES-1,0,"'Q' to quit, '0'..'%d' to bounce",num_msg-1);

    return num_msg;
}


void *animate(void *arg)
{
    struct propset *info = (struct propset *)arg;       
    int len = strlen(info->str)+2;  
    int col = rand()%(COLS-len);    

    while(1)
    {
        usleep(info->delay*TUNIT);

        pthread_mutex_lock(&mx);
           move( info->row, col );  
           addch(' ');      
           addstr( info->str );     
           addch(' ');  
           move(LINES-1,COLS-1);    
           refresh();       
        pthread_mutex_unlock(&mx);


        pthread_mutex_lock(&info->myMutex);

        col += info->dir;

        if ( col <= 0 && info->dir == -1 )
            {
                info->dir = 1;  

                usleep(info->delay*TUNIT);

                pthread_mutex_lock(&mx);
                   move( info->row, col );
                   addch(' ');          
                   addstr( info->str );     
                   addch(' ');          
                   move(LINES-1,COLS-1);    
                   refresh();           
                pthread_mutex_unlock(&mx);  

                col+=info->dir;
            }
        else if (  col+len+1 >= COLS && info->dir == 1 )
            {
                info->dir = -1;

                usleep(info->delay*TUNIT);

                pthread_mutex_lock(&mx);    
                   move( info->row, col );  
                   addch(' ');          
                   addstr( info->str );     
                   addch(' ');          
                   move(LINES-1,COLS-1);    
                   refresh();           
                pthread_mutex_unlock(&mx);  

                col+=info->dir; 
            }

        pthread_mutex_unlock(&info->myMutex);   
    }
}

static StrAttribute
getStr(void)
{
    char buffer[MSGLEN]={0};
    static char *avBuf[MAXMSG]={0};
    unsigned char count=0;
    StrAttribute ret;

    while(count<MAXMSG && fgets(buffer,MSGLEN,stdin)!=NULL)
    {
        avBuf[count]=(char *)calloc(strlen(buffer)+1,sizeof(char));
        strcpy(avBuf[count],buffer);
        if(avBuf[count][strlen(buffer)-1]=='\n')
            avBuf[count][strlen(buffer)-1]='\0';
        memset(buffer,0,strlen(buffer));
        ++count;
    }

    ret.avPtr=avBuf;
    ret.num=count;

    return ret;
}

static void 
freeStr(StrAttribute arg)
{
    int i=0;
    for(;i<arg.num;++i)
    {
        free(arg.avPtr[i]);
    }
}

int main(void)
{
    pthread_t thrds[MAXMSG];    /* the threads      */
    void *animate();    /* the function     */
    int num_msg ;   /* number of strings    */
    int i;
    StrAttribute ret;
    int ac;
    char **av;
    int c;

    ret=getStr();
    ac=ret.num;
    av=ret.avPtr;

    num_msg = setup(ac,av,props);

    /* create all the threads */
    for(i=0 ; i<num_msg; i++)
        if ( pthread_create(&thrds[i], NULL, animate, &props[i])){
            fprintf(stderr,"error creating thread");
            endwin();
            exit(0);
        }

    /* process user input */
    while(1) 
    {
        c = getch();

        if ( c == 'Q' ) 
            break;
        else if ( c == ' ' )
            for(i=0;i<num_msg;i++)
            {
                pthread_mutex_lock(&props[i].myMutex);
                props[i].dir = -props[i].dir;
                pthread_mutex_unlock(&props[i].myMutex);
            }
        else if ( c >= '0' && c <= '9' )
            {
                i = c - '0';
                if ( i < num_msg )
                    {
                        pthread_mutex_lock(&props[i].myMutex);
                        props[i].dir = -props[i].dir;                   
                        pthread_mutex_unlock(&props[i].myMutex);    
                    }
            }
    }

    /* cancel all the threads */
    pthread_mutex_lock(&mx);

    for (i=0; i<num_msg; i++ )
        pthread_cancel(thrds[i]);

    for(i=0;i<num_msg;++i)
        pthread_join(thrds[i],NULL);

    for(i=0;i<num_msg;++i)
        pthread_mutex_destroy(&props[i].myMutex);

    pthread_mutex_unlock(&mx);

    freeStr(ret);   
    endwin();
    return 0;
}
查看全部
pilepilepile
pilepilepile
2020/08/31 16:33
  • c语言
  • linux
  • unix
  • centos
  • 点赞
  • 收藏
  • 回答
    私信

1个回复