[英]Socket blocked by pause()
我正在研究接受傳入TCP連接的軟件,並且遇到了一些我不理解的東西。 首先,我將解釋軟件基本上在做什么。 請記住,有些部分是暫時的,我知道這很可能是一種糟糕的做事方式,但在原型設計過程中,我遇到了這個問題。
我有主進程為SIGINT建立一個信號處理程序。 然后主進程啟動一個新線程,將其稱為'listener',使用pthread_create()默認值。 偵聽器首先打開套接字,綁定,偵聽並設置套接字非阻塞。 然后,偵聽器將使用select()輪詢套接字,等待傳入連接。
現在,如果我在主線程中有一個啞的while(1)循環,我可以毫無問題地連接到套接字。 問題是:如果我用pause()替換while(1)循環,我就不能再連接到套接字了。 我知道監聽器線程仍然通過日志消息激活。 同樣,我不打算使用pause(),但我只是想知道發生了什么。
pause()阻止某個信號到達子線程嗎?
更新:我提供的精簡代碼似乎沒有表現出相同的行為。 如果我能確定原因,我會再次更新。
更新2:我發現了這個問題。 我發布的代碼與我的問題代碼之間存在一個重要區別。 以下是不同之處:
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);
}
從OS man pause
OS X:
DESCRIPTION
Pause is made obsolete by sigsuspend(2).
The pause() function forces a process to pause until a signal is received
from either the kill(2) function or an interval timer. (See
setitimer(2).) Upon termination of a signal handler started during a
pause(), the pause() call will return.
從man pause
Linux:
DESCRIPTION
pause() causes the calling process (or thread) to sleep until a signal
is delivered that either terminates the process or causes the invoca‐
tion of a signal-catching function.
兩個手冊頁都暗示調用進程將休眠。 這解釋了無法調用accept()
。
你能確定是否正在調用accept()
嗎? 您是否在適當的情況下檢查所有返回狀態和errno
?
我不確定睡眠線程的目的是什么。 如果必須保持主線程處於活動狀態,為什么不使用類似sleep()
調用的while循環? (也許你打算稍后在這里添加代碼來進行輪詢?在這種情況下,使用usleep()
以及你想要檢查的任何間隔,或者sleep(1)
如果每秒一次的粒度是否足夠?)或者只是運行你的select()
在主線程上。
編輯:看起來程序正在運行給我。 我把它修改如下:
--- /tmp/foo.c 2014-02-11 16:43:04.000000000 -0800
+++ /tmp/foo.c 2014-02-11 16:46:17.000000000 -0800
@@ -7,6 +7,7 @@
#include <signal.h>
#include <sys/select.h>
#include <unistd.h>
+#include <stdio.h>
pthread_t thread_id;
@@ -76,6 +77,7 @@
}
status = select(fdsMax + 1, &readSet, NULL, NULL, &timeout);
+ printf("select() woke up\n");
}
return NULL;
}
當我進行上述更改時,它會打印select() woke up
每半秒select() woke up
一次,直到我連接到套接字。 然后它反復打印它。
你能更好地描述你看到的行為嗎? 是否存在阻塞的調用,例如讀取或寫入套接字?
你可以附加(或運行) gdb
並找出每個線程正在做什么?
以下程序顯示在主線程暫停時線程繼續運行。 再加上Mike無法在兩個獨立的平台上重現您的問題,我認為請您重新確認您真正看到上述內容是公平的。
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#define exitOnErr(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
static void handler(int sig)
{
printf("don't use printf in a signal handler\n");
}
void *athread(void* x)
{
while (1)
{
printf("thread running\n");
sleep(1);
}
}
int main(int argc, char *argv[])
{
printf("%d\n", getpid());
pthread_t pid;
if (signal(SIGINT, handler) == SIG_ERR)
exitOnErr("signal");
if(pthread_create(&pid, NULL, athread, NULL) != 0)
exitOnErr("pthread_create");
while(1)
{
pause();
printf("pause returned\n");
}
}
殺死-SIGINT“pid”並殺死-SIGTERM“pid”。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.