0

我正在做一个项目,我需要从 80 个或更多客户端读取数据,然后将他们的 o/p 连续写入文件,然后读取这些新数据以执行另一项任务。我的问题是我应该使用选择还是多线程?

我还尝试使用 read/fgets 和 write/fputs 调用来使用多线程,但由于它们是阻塞调用,并且一次可以执行一项操作,因此这是不可行的。任何想法都非常感谢。

更新 1:我尝试使用条件变量来实现相同的功能。我能够做到这一点,但它一次写入和读取一个。当另一个客户端尝试写入时,除非我退出第一个线程,否则它无法写入。我不明白。现在应该可以了。我在做什么错误?

更新2:谢谢大家..我能够成功地使用互斥条件变量实现这个模型。

更新后的代码如下:

        **header file*******
         char    *mailbox ;
    pthread_mutex_t  lock  = PTHREAD_MUTEX_INITIALIZER ;
    pthread_cond_t   writer = PTHREAD_COND_INITIALIZER;

    int main(int argc,char *argv[])
    {
      pthread_t          t1 , t2;
      pthread_attr_t     attr;
      int            fd, sock , *newfd;
      struct sockaddr_in cliaddr;
      socklen_t      clilen;
      void          *read_file();
      void          *update_file();

      //making a server socket
      if((fd=make_server(atoi(argv[1])))==-1)
        oops("Unable to make server",1)


      //detaching threads
      pthread_attr_init(&attr);
      pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);

      ///opening thread for reading
      pthread_create(&t2,&attr,read_file,NULL);

      while(1)
      {
        clilen = sizeof(cliaddr);
        //accepting request
        sock=accept(fd,(struct sockaddr *)&cliaddr,&clilen);

        //error comparison against failire of request and INT
        if(sock==-1 && errno != EINTR)
                oops("accept",2)
        else if ( sock ==-1 && errno == EINTR)
            oops("Pressed INT",3)

        newfd = (int *)malloc(sizeof(int));
        *newfd = sock;
        //creating thread per request
        pthread_create(&t1,&attr,update_file,(void *)newfd);
      } 
     free(newfd);
     return 0;
    }

    void *read_file(void *m)
    {
        pthread_mutex_lock(&lock);
        while(1)
        {
            printf("Waiting for lock.\n");
        pthread_cond_wait(&writer,&lock);
            printf("I am reading here.\n");
            printf("%s",mailbox);
            mailbox = NULL ;
        pthread_cond_signal(&writer);
        }
    }


    void *update_file(int *m)
    {
       int  sock = *m;
       int  fs ; 
       int  nread;
       char buffer[BUFSIZ] ;

       if((fs=open("database.txt",O_RDWR))==-1)
          oops("Unable to open file",4)

       while(1)
       {
        pthread_mutex_lock(&lock);
        write(1,"Waiting to get writer lock.\n",29);

        if(mailbox != NULL)
           pthread_cond_wait(&writer,&lock);

            lseek(fs,0,SEEK_END);
            printf("Reading from socket.\n");
            nread=read(sock,buffer,BUFSIZ);
            printf("Writing in file.\n");
            write(fs,buffer,nread);
            mailbox = buffer ;
          pthread_cond_signal(&writer);
          pthread_mutex_unlock(&lock);
       }
        close(fs);
    }
4

3 回答 3

1

我认为对于事物的网络部分,每个客户端线程或多路复用单线程都可以正常工作。

至于磁盘 I/O,你说得对,磁盘 I/O 操作是阻塞操作,如果你的数据吞吐量足够高(和/或你的硬盘驱动器足够慢),如果磁盘 I/O 是同步完成的。

如果这对您来说是一个实际问题(并且您应该首先进行测量以验证它是否确实是一个问题;如果您不需要,则没有必要使事情复杂化),那么我试图改善问题的第一件事就是通过调用setbuffer来增大文件的输出缓冲区。有了足够大的缓冲区,C 运行时库就有可能隐藏由磁盘访问引起的任何延迟。

如果更大的缓冲区不够用,接下来我会尝试创建一个或多个专用于读取和/或写入数据的线程。也就是说,当您的网络线程想要将数据保存到磁盘时,它不是直接调用 fputs()/write(),而是分配一个包含它要写入的数据的缓冲区,并通过 (互斥保护或无锁)FIFO 队列。然后 I/O 线程将该缓冲区从队列中弹出,将数据写入磁盘,然后释放缓冲区。I/O 线程可以承受偶尔缓慢的写入,因为没有其他线程被阻塞等待写入完成。线程读取磁盘稍微复杂一些,但基本上 IO 读取线程会填满一个或多个内存数据缓冲区,以供网络线程耗尽;每当网络线程从缓冲区中排出一些数据时,它都会向 IO-read 线程发出信号以再次将缓冲区重新填充到顶部。这样(理想情况下)每当网络线程需要将一些输入数据发送到客户端时,RAM中总是已经存在大量输入数据。

请注意,上面的多线程方法要正确使用有点棘手,因为它涉及线程间同步和通信;所以不要这样做,除非没有任何更简单的替代方案就足够了。

于 2013-10-16T06:34:14.697 回答
0

如果您的程序解决了问题,选择/轮询或多线程都可以。

我猜随着客户端数量的增加,您的程序将受到 io-bound,因为您经常读取/写入磁盘。因此,让多个线程执行 io 操作不会加快速度。那么投票可能是更好的选择

于 2013-10-16T05:19:25.983 回答
0

您可以将从accept中获取的套接字设置为非阻塞。然后很容易使用select找出何时有数据,读取可用字节数并处理它们。

对于(仅)80 个客户端,我认为没有理由期望使用线程有任何显着差异,除非您从不同客户端获得非常不同数量的数据。

于 2013-10-16T06:35:35.463 回答