c-socket用于多线程



我阅读了关于多线程中使用的套接字的代码,代码如下:

功能主

int main(void)
{
int listenfd;
int i = 0;
/* check envirenment */
if (check_env() == FALSE)
{
return 0;
}
/* get the bind port */
listenfd = initserver(PORT); 
if ( listenfd == -1 )
{
return 0;
}
/* initial the message queue. */
/* and start to run ...*/
initDatas(listenfd);
/* start already.........*/
/* make the main thread be a thread which recive the requst from 
* client */
fMsgIn((void *)&listenfd);
return 0;
}

函数initDatas

void initDatas(socketfd fd)
{
int num_accept_req      = 5;
int num_go              = 5;
int num_getblg          = 5;
/* control userbuf */
init_userbuf();
/* init the ctrlsockfd list */
init_ctrlsockfd();
/* run server */
init_accept_req(fd, num_accept_req);
/* get blog  */
init_getblg(num_getblg);
/* put blog */
//    init_pubblg(num_pubblg);
/* get personal msg */
//   init_getprsnalmsg(num_getprsnalmsg);
/* pub personal msg */
//  init_pubprsnalmsg(num_pubprsnalmsg);
/*get followers */
// init_getfollower(num_getfollower);
/* set personal information */
//init_setprsnalinfo(num_setprsnalinfo);
/* send out dates ...*/
init_msgout(num_go);
}

函数init_accept_req

void init_accept_req(socketfd fd, int number_thread)
{
#ifdef DEBUG
printf("ninitial thread for accept request !n");
ASSERT(number_thread >= 1 && fd > 0);
#endif
pthread_t *pid;
pthread_attr_t attr;
int i = 0;
pid = Malloc_r(number_thread * sizeof(pthread_t));
if ( pid == NULL )
err_quit("malloc, in init_accept_req");
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
for ( i = 0; i < number_thread; i++ )
{
/* control accept requst */
pthread_create(pid + i, &attr, (void *)fMsgIn, (void*)&fd);
}
}

我们可以看到,套接字文件描述符listenfd是由函数initserver创建的,在函数init_accept_req中,创建了多线程,并在这些线程的回调函数中调用了linux套接字函数accept,即函数fMsgIn,所以我的问题是,当多线程使用同一个套接字fd时,这些线程之间没有任何冲突吗?(请注意,当调用linux套接字函数accept时,这些线程中没有同步原语)?

回答问题:

在同一个套接字上列出多个线程确实有效,就像最近的实现一样,accept()是线程保存。

然而,必须小心检查所有这些并行accept()的结果,因为在尝试连接的客户端上可能会返回多个tehm,但只有一个accept()这样做不会出错。

此外,有人可能会认为,由于这些多重回报,这种情况效率低下。


但是这些调用

for ( i = 0; i < number_thread; i++ )
{
pthread_create(pid + i, &attr, (void *)fMsgIn, (void*)&fd);
}

创建线程是潜在的杀手,因为它们向下传递给线程函数对本地变量的引用

void init_accept_req(socketfd fd, int number_thread);

即CCD_ 10。

一旦init_accept_req()返回,fd就不再有效,传递给线程函数的引用所指向的也不再有效。

要解决此问题,请向下传递对侦听套接字的引用,如下所示:

void init_accept_req(socketfd * pfd, int number_thread)
{
[...]
for ( i = 0; i < number_thread; i++ )
{
/* control accept requst */
pthread_create(pid + i, &attr, (void *)fMsgIn, (void*) pfd);
}
}
void initDatas(socketfd * pfd)
{
[...]
init_accept_req(pfd, num_accept_req);
[...]
int main(void)
{
int listenfd;
/* initial the message queue. */
/* and start to run ...*/
initDatas(&listenfd);
[...]

使用这种方法,只需要确保main()确实结束(以便侦听套接字listenfd保持有效),只要任何接受线程都在做它们的工作。

有点脏的解决方案是将线程函数的void *类型的用户数据参数滥用为int,并按如下值传递套接字描述符:

pthread_create(pid + i, &attr, (void *)fMsgIn, (void*) fd);

不好,但只要sizeof(void*)不小于sizeof(int),就可行。

通常情况下,在没有同步的情况下从多个线程对一个套接字进行操作是个坏主意,尽管这并不被禁止。例如,您可以有一个线程读取和一个线程写入。但是,如果您尝试让两个线程都读取,或者两个线程同时写入,那么如果没有任何同步,您可能不会得到合理的结果。类似地,如果您在一个线程中close()没有同步,您将遇到麻烦,因为另一个线程可能最终访问不存在的FD。

据我所知,在你试图实现的方案中,do有一些同步。当你在主线程中accept时,你会得到一个新的fd,然后你将其传递给负责它的子线程。在accept发生后(更重要的是在pthread_create()输入后),你的主线程保证不会处理该fd。您发布的代码示例并不完整,因此很难判断您是否真的实现了这一点(例如,我看不出在哪里调用accept)。

Stephens关于高级UNIX编程的书也是这方面的宝贵资源;它提供了许多分叉、非分叉和线程服务器和客户端的示例。

相关内容

  • 没有找到相关文章

最新更新