C 为什么线程函数的参数应该在堆中?
我使用pthread库用c编写了一个多客户端服务器。当每个客户端尝试连接到服务器时,每个客户端作为单独的线程运行,并使用handle_client函数处理每个客户端C 为什么线程函数的参数应该在堆中?,c,multithreading,pthreads,C,Multithreading,Pthreads,我使用pthread库用c编写了一个多客户端服务器。当每个客户端尝试连接到服务器时,每个客户端作为单独的线程运行,并使用handle_client函数处理每个客户端 void* handle_client(void* connfd) { /* read a string sent by the client, * print it and then send the string * "Hello from the server" to the client*/
void* handle_client(void* connfd)
{
/* read a string sent by the client,
* print it and then send the string
* "Hello from the server" to the client*/
int sock = *(int*)connfd;
int read_size;
char *message , client_message[2000];
//Send some messages to the client
message = "Hello from the server\n";
write(sock , message , strlen(message));
while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
{
//end of string marker
client_message[read_size] = '\0';
//Send the message back to client
puts(client_message);
//clear the message buffer
memset(client_message, 0, 2000);
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
free(connfd);
return NULL;
}
我想知道为什么我需要将connfd声明为堆中的变量?如果将其声明为局部变量,会出现什么问题
这是生成每个线程的代码(在main()函数中)
为使代码正常工作,必须确保:
- 包含连接句柄的变量(在您的代码中,
)只要*connfd
线程需要它就存在李>handle\u客户端
- 它的值不会被
循环的后续迭代所覆盖while
通常,将本地(自动、基于堆栈的)变量的地址传递给线程函数并不一定是错误的。它只需要比使用基于堆的变量更加小心。要使代码正常工作,必须确保:
- 包含连接句柄的变量(在您的代码中,
)只要*connfd
线程需要它就存在李>handle\u客户端
- 它的值不会被
循环的后续迭代所覆盖while
- 变量的生命周期可能在线程中使用之前结束。在对象生存期后访问对象具有未定义的行为
- 在C11之前,没有为从其他线程访问本地变量指定任何行为。由于行为未定义,因此它是隐式未定义的
- C11表示从另一个线程访问自动变量的行为是实现定义的: 其标识符声明为无链接且没有存储类说明符static的对象具有自动存储持续时间,某些复合文字也是如此。尝试从与对象关联的线程以外的线程间接访问具有自动存储持续时间的对象的结果由实现定义 你看过编译器手册了吗 GCC表示: 支持此类访问,但并发访问的同步要求与对任何对象的并发访问的同步要求相同
- 即使支持访问,也可能存在数据竞争,包括编译器决定不再需要该值
- 变量的生命周期可能在线程中使用之前结束。在对象生存期后访问对象具有未定义的行为
- 在C11之前,没有为从其他线程访问本地变量指定任何行为。由于行为未定义,因此它是隐式未定义的
- C11表示从另一个线程访问自动变量的行为是实现定义的: 其标识符声明为无链接且没有存储类说明符static的对象具有自动存储持续时间,某些复合文字也是如此。尝试从与对象关联的线程以外的线程间接访问具有自动存储持续时间的对象的结果由实现定义 你看过编译器手册了吗 GCC表示: 支持此类访问,但并发访问的同步要求与对任何对象的并发访问的同步要求相同
- 即使支持访问,也可能存在数据竞争,包括编译器决定不再需要该值
这些点中没有一点适用于在另一个线程启动后动态分配且未修改的对象。如果使用局部变量,它将在主线程堆栈中初始化。将该变量的地址传递给各个线程是安全的,因为主线程的堆栈变量生命周期显然足够长但这样做的问题是每次在同一个局部变量中(1)更新fd值,这将使每个线程使用该值,从而导致未定义的行为
因此,您必须在堆或堆栈中为每个线程分配新变量,以便每个线程都能够读取正确的fd值,而不会产生任何歧义。如果使用局部变量,它将在主线程的堆栈中初始化。将该变量的地址传递给各个线程是安全的,因为主线程的堆栈变量生命周期显然足够长但这样做的问题是每次在同一个局部变量中(1)更新fd值,这将使每个线程使用该值,从而导致未定义的行为
因此,您必须在堆或堆栈中为每个线程分配新变量,以便每个线程能够读取正确的fd值,而不会产生任何歧义。请注意,在代码中,您正在向未初始化的自动
客户机传递指针
void* handle_client(void* connfd)
{
/* read a string sent by the client,
* print it and then send the string
* "Hello from the server" to the client*/
int sock = *(int*)connfd;
int read_size;
char *message , client_message[2000];
//Send some messages to the client
message = "Hello from the server\n";
write(sock , message , strlen(message));
while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
{
//end of string marker
client_message[read_size] = '\0';
//Send the message back to client
puts(client_message);
//clear the message buffer
memset(client_message, 0, 2000);
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
free(connfd);
return NULL;
}