循环访问pthread互斥锁的线程

时间:2010-02-23 14:28:54

标签: c linux multithreading scheduling mutex

我正在构建这个应用程序,其中我有一个由线程表示的客户端,在循环中运行(直到它收到终止指令),试图访问服务器中的关键数据部分。

当第一个客户端连接到服务器时,他拥有对该互斥锁的锁定。所有后续连接都被搁置。这是它的“正常”部分。

但是,当第一个线程解锁时,循环将它带回到开始,它应该再次争夺锁定。但是假设他仍然持有锁并在几乎无限循环中执行临界区(不是无限的,因为我们可以终止线程,为其他线程提供锁定)。

要恢复所有...当第一个客户端连接时,它永远拥有锁。其他线程保持在等待行中,直到第一个线程终止。这是一些代码:

服务器:

int main(int argc, char * argv[])
{
    int servSock;     
    unsigned short servPort;  
    unsigned int clntLen;

    rcvBuf = (char *)malloc((MAXLINE)*sizeof(char));
    pthreads = (fifo_t*)malloc(sizeof(fifo_t));

    struct sockaddr_in servAddr; 
    struct sockaddr_in clntAddr; 

    pthread_attr_t custom_sched_attr;   

    int fifo_max_prio, fifo_min_prio, fifo_mid_prio;   
    struct sched_param fifo_param;    

    pthread_attr_init(&custom_sched_attr);   
    pthread_attr_setinheritsched(&custom_sched_attr, PTHREAD_EXPLICIT_SCHED);   
    pthread_attr_setschedpolicy(&custom_sched_attr, SCHED_FIFO);

    fifo_max_prio = sched_get_priority_max(SCHED_FIFO);   
    fifo_min_prio = sched_get_priority_min(SCHED_FIFO);   
    fifo_mid_prio = (fifo_min_prio + fifo_max_prio)/2;   

    fifo_param.sched_priority = fifo_mid_prio;  

    pthread_attr_setschedparam(&custom_sched_attr, &fifo_param);

    if(argc !=2 ){
        fprintf(stderr,"Usage: %s <Server Port>\n",argv[0]);
        exit(1);
    }

    fifo_init(pthreads);

    db  = db_open("DB", O_RDWR, 0666);
    servPort = atoi(argv[1]);

    if((servSock = socket(AF_INET,SOCK_STREAM,0)) < 0){ 
        perror("Error with Socket()");
        exit(1);
    }

    memset(&servAddr,0,sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port = htons(servPort);

    if(bind(servSock,(struct sockaddr*)&servAddr,sizeof(servAddr)) < 0){
        perror("Error with bind()");
        exit(1);
    }

    if(listen(servSock,NUM_THREADS) < 0){
        perror("Error with listen()");
        exit(1);
    }

    for(;;)
    { 
        printf("A estabelecer ligaçao!\n");
        clntLen = sizeof(clntAddr);

        if((clntSock = accept(servSock,(struct sockaddr*)&clntAddr,&clntLen)) < 0)
        {
            perror("Error with accept()");
            exit(0);
        }

        printf("Ligação estabelecida!\n");

        pthread_create(&thread,&custom_sched_attr,&HandleTcpClient,(void *)clntSock);

        printf("Continua a execução nesta thread: %d\n",(int)pthread_self());
   }

   exit(0);
}

void * HandleTcpClient(void * data){

   insert(pthreads,(int)pthread_self());

   int sock = (int)data;

   char * key = (char *)malloc(FIELD * sizeof(char));
   char * dados = (char *)malloc(FIELD * sizeof(char));
   char * vendDev = (char *)malloc(FIELD * sizeof(char));
   char * str = (char*)malloc(MAXLINE * sizeof(char));

   memset(key,0,sizeof(key));
   memset(dados,0,sizeof(dados));
   memset(vendDev,0,sizeof(vendDev));
   memset(str,0,sizeof(str));

   while(1)
   {
   start:

       printf("Sem Lock: %d com socket: %d\n",(int)pthread_self(),sock);

       pthread_mutex_lock(&mutexdb);

       printf("Com Lock: %d com socket: %d\n",(int)pthread_self(),sock);
       int i = 0;
       char op;

       if((recvMsgSize = recv((sock),rcvBuf,MAXLINE,0)) &lt; 0)
       {
           perror("Erro na recepção!\n");
           exit(-1);
       }

       rcvBuf[recvMsgSize]='\0';
       str = (char *)rcvBuf;

       op = *str++;

       while(*str!='|' && *str!=0){
           key[i]=*str;
           str++;
           i++;
       }

       key[++i]='\0';
       str++;

       if((int)op==2 || (int)op==3) strcpy(vendDev,str);  // obter o numero de produtos vendidos/devolvidos
       else strcpy(dados,str);

       if(op == 4 || op == 6)
       {
           db_operate(&db,op,key,dados,sock); 
           pthread_mutex_unlock(&mutexdb);
           printf("Unlock: %d com socket: %d\n",(int)pthread_self(),sock);
           goto start;
       }
       else
           if(op == 7)
           {
               extract(pthreads);
               pthread_mutex_unlock(&mutexdb);
               close(sock);
               pthread_exit(0);
               break;
           }
           else
               if(op == 1 || op == 2 || op == 3 || op == 5)
               {
                   db_search(&db,op,key,vendDev,sock);
                   pthread_mutex_unlock(&mutexdb);
                   printf("Unlock: %d com socket: %d\n",(int)pthread_self(),sock);
                   goto start;
               }
   }

谁能告诉我这里我做错了什么?我如何实现一个策略,当第一个线程解锁时,下一个线程获得它并且所述第一个线程返回到等待线,就像在FIFO列表中一样?

谢谢;)

1 个答案:

答案 0 :(得分:4)

发布的代码有很多问题:

  • 线程函数分配内存但从不释放它。
  • 你把互斥锁放在阻塞套接字读取上 - 这绝不是个好主意。互斥锁应该保护线程之间共享的 资源 - 您的情况下的数据库。套接字不共享,因此不需要保护。更糟糕的是 - 等待套接字并持有互斥锁会阻止其他线程访问数据库。
  • 在设计方面 - 互斥锁属于数据库,而不是套接字读取器。我建议  将互斥锁添加到db结构,在数据库设置时初始化它,并在db访问函数中隐藏锁定/解锁调用。识别 最小的关键部分 并保护它。这为您提供了更好的并发性。
  • 执行每插槽线程仅适用于非常少量的连接。大规模设计几乎总是涉及非阻塞套接字和select/poll/epoll/kqueue技巧。

我并不真正理解问题的先入为主的部分,但我希望上述各点能引导你走向正确的方向。