我正在开发一个项目,其中我需要从 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);
}
我认为对于网络部分,每个客户端线程或多路复用单线程都可以正常工作。
至于磁盘 I/O,您说得对,磁盘 I/O 操作是阻塞操作,如果您的数据吞吐量足够高(和/或您的硬盘驱动器足够慢),它们可能会减慢您的网络操作,如果磁盘 I/O 是同步完成的。
如果这对您来说是一个实际问题(并且您应该首先测量以验证它确实是一个问题;如果您不需要,则没有必要使事情复杂化),我要尝试改善问题的第一件事是通过调用 setbuffer 使文件的输出缓冲区更大。有了足够大的缓冲区,C 运行时库就有可能隐藏由磁盘访问引起的任何延迟。
如果较大的缓冲区还不够,我要尝试的下一件事是创建一个或多个专用于读取和/或写入数据的线程。也就是说,当您的网络线程想要将数据保存到磁盘时,它不是直接调用 fputs()/write(),而是分配一个包含要写入的数据的缓冲区,并通过 (互斥锁保护或无锁) FIFO 队列。然后,I/O 线程将该缓冲区从队列中弹出,将数据写入磁盘,并释放缓冲区。 I/O 线程可以承受偶尔写入缓慢的情况,因为没有其他线程被阻塞等待写入完成。从磁盘进行线程读取稍微复杂一些,但基本上 IO 读取线程会填充一个或多个内存数据缓冲区,以便网络线程耗尽;每当网络线程从缓冲区中耗尽一些数据时,它就会向 IO 读取线程发出信号,将缓冲区重新填充到顶部。这样(理想情况下)每当网络线程需要向客户端发送一些输入数据时,RAM 中总是存在大量输入数据。注意,上面的多线程方法有点棘手,因为它涉及线程间同步和通信;所以不要这样做,除非没有任何更简单的替代方案就足够了。
我猜随着客户端数量的增加,你的程序将受到 io 限制,因为你经常进行磁盘读/写。因此,多个线程执行 io 操作不会加快速度。那么投票可能是更好的选择
accept
获得的套接字设置为非阻塞。然后很容易使用
select
来查找何时有数据,读取可用的字节数并处理它们。对于(仅)80 个客户端,我认为没有理由期望使用线程有任何显着差异,除非您从不同的客户端获得非常不同的数据量。