【发布时间】:2014-02-11 23:57:00
【问题描述】:
我正在开发接受传入 TCP 连接的软件,但遇到了一些我不理解的问题。首先,我将解释该软件的基本作用。请记住,有些部分是临时的,我知道这很可能是一种糟糕的做事方式,但在原型制作过程中我遇到了这个问题。
我让主进程为 SIGINT 建立一个信号处理程序。然后主进程启动一个新线程,将其称为“侦听器”,默认为 pthread_create()。侦听器首先打开一个套接字,绑定、侦听并将套接字设置为非阻塞。然后监听器将使用 select() 轮询套接字,等待传入的连接。
现在,如果我在主线程中有一个愚蠢的 while(1) 循环,我可以毫无问题地连接到套接字。问题是:如果我用 pause() 替换 while(1) 循环,我将无法再连接到套接字。我知道侦听器线程仍然通过日志消息处于活动状态。同样,我不打算使用 pause(),但我只想知道发生了什么。
pause() 是否会阻止某个信号到达子线程?
更新:我提供的精简代码似乎没有表现出相同的行为。如果我能确定原因,我会再次更新。
UPDATE2:我发现了问题所在。我发布的代码和我的问题代码之间存在一个关键区别。以下是区别:
static void* listener_thread(void* arg)
{
int listen_port = *(int *)arg;
int listen_fd;
fd_set readSet;
int fdsMax, status;
struct timeval timeout;
if(open_listen_port(listen_port, &listen_fd) == -1)
...
int start_listener_thread(int port)
{
int status = 0;
if(0 > pthread_create(&thread_id, NULL, listener_thread, (void *)&port))
在 main.c 中:
if(0 == status && -1 == start_listener_thread(3000))
所以你可以看到我将端口号作为指向堆栈位置的指针传递给线程。不是一个好主意。奇怪的是,如果我将 pause() 更改为 while(1) 循环,它会起作用。而使用 pause() 端口号恰好是一个有效端口。
在 start_listener_thread 中为端口号分配空间解决了这个问题。感谢一路上的帮助!
代码示例(精简):
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/select.h>
#include <unistd.h>
pthread_t thread_id;
void sighandler(int signum)
{
}
int open_listen_port(int listenPort, int* listenFd)
{
struct sockaddr_in listenAddr;
int flags;
memset(&listenAddr, 0, sizeof(listenAddr));
listenAddr.sin_family = AF_INET;
listenAddr.sin_port = htons(listenPort);
listenAddr.sin_addr.s_addr = INADDR_ANY;
if( (*listenFd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
{
return(-1);
}
if( bind(*listenFd, (struct sockaddr*) &listenAddr,
sizeof(listenAddr)) == -1 )
{
return(-1);
}
if( listen(*listenFd, 16) == -1 )
{
return(-1);
}
// change listener to be non-blocking
flags = fcntl(*listenFd, F_GETFL);
if(fcntl(*listenFd, F_SETFL, flags | O_NONBLOCK) == -1)
{
return(-1);
}
return (0);
}
static void* listener_thread(void* arg)
{
int listen_fd;
fd_set readSet;
int fdsMax, status;
struct timeval timeout;
if(open_listen_port(3000, &listen_fd) == -1)
{
pthread_exit(NULL);
}
while(1)
{
FD_ZERO(&readSet);
fdsMax = 0;
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
FD_SET(listen_fd, &readSet);
if(listen_fd > fdsMax)
{
fdsMax = listen_fd;
}
status = select(fdsMax + 1, &readSet, NULL, NULL, &timeout);
}
return NULL;
}
int start_listener_thread()
{
int status = 0;
if(0 > pthread_create(&thread_id, NULL, listener_thread, NULL))
{
status = -1;
}
return(status);
}
int main(int argc, char *argv[])
{
struct sigaction sigopt;
int status = 0;
memset(&sigopt, 0, sizeof(struct sigaction));
sigopt.sa_handler = sighandler;
if(0 != sigaction(SIGINT, &sigopt, NULL))
{
status = -1;
}
if(0 == status && -1 == start_listener_thread())
{
status = -1;
}
pause();
return(0);
}
【问题讨论】:
-
pause挂起当前线程。给我们看一个代码示例怎么样?
标签: c linux multithreading sockets signals