我正在用C做一个并发服务器以接受连接,它们将向我发送数据包中的字节,并且我需要在单独的线程中参与每个连接。我正在使用 Pthread_create()创建线程并在线程的例程内部,我正在调用一个函数来处理字节(数据包)的读取。
我注意到,第一个线程可以完美地完成所有工作,但是,第二个线程以及第二个线程之后的任何线程,程序只会挂起,并且永远不会做其他事情。
#include "csapp.h"
// Prototypes
void *thread(void *vargp);
void doProcess(int connfd, int portno);
struct threadArgu {
int *connfdp;
int portno;
};
/**
* Thread-Based Concurrent Server
*/
int main(int argc, char *argv[]) {
char* portno;
int listenfd, *connfdp;
socklen_t clientlen;
struct sockaddr_storage clientaddr;
if (argc < 2) {
fprintf(stderr, "ERROR, no port provided\n");
exit(1);
}
// The port number on which the server will listen for connections is passed in as an argument.
portno = argv[1];
listenfd = Open_listenfd(portno);
// Makes the server capable of handling a number of simultaneous connections, each in its own thread.
while (1) {
// Connection
clientlen = sizeof(struct sockaddr_storage);
connfdp = Malloc(sizeof(int)); // Malloc of connected descriptor necessary to avoid deadly race
*connfdp = Accept(listenfd, (SA *) &clientaddr, &clientlen);
// Thread arguments
args = calloc(1, sizeof(struct threadArgu));
args->connfdp = connfdp;
args->portno = atoi(portno);
// Create thread
pthread_t tid;
Pthread_create(
&tid, // The actual thread object that contains pthread id
NULL, // Attributes to apply to this thread
thread, // The function this thread executes
args // Arguments to pass to thread function above
);
}
}
/**
* Thread routine
*/
void *thread(void *vargp) {
struct threadArgu *args = (struct threadArgu *) vargp;
int connfdp = *((int *) args->connfdp);
int portno = args->portno;
printf("connfdp: %d\n", connfdp);
printf("portno: %d\n", portno);
Pthread_detach(pthread_self()); // Run thread in "detached mode"
Free(args); // Free storage allocated
doProcess(connfdp, portno); // Starts the work that this thread will do
Close(connfdp);
return NULL; // Peer thread terminates
}
/**
* Starts the logic to read the messages and work with the bytes
* @param connfd The connection file descriptor
* @param portNo The port number of the connection
*/
void doProcess(int connfd, int portNo) {
size_t n;
char buf[MAXLINE];
rio_t rio;
Rio_readinitb(&rio, connfd);
while ((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) {
// Read the bytes and saves it
Rio_readnb(&rio, tmpVariable->packet.data, numberOfBytes);
}
}
请记住,每个连接都有自己的线程,自己的端口号,而我的函数doProcess()只是执行逻辑以一次从单个连接读取字节。这不是线程安全的!。
使用调试器工具,我可以看到线程#1此时位于(这在csapp.c库的函数内部):
void Pthread_join(pthread_t tid, void **thread_return) {
int rc;
if ((rc = pthread_join(tid, thread_return)) != 0) // <-- Is here
posix_error(rc, "Pthread_join error");
}
并且线程#2此时是(这是我的功能):
void doProcess(int connfd, int portNo) {
size_t n;
char buf[MAXLINE];
rio_t rio;
Rio_readinitb(&rio, connfd);
while ((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) { // <-- Is here
}
}
我认为有多个线程正在调用我的函数并使我的函数逻辑发疯。
我的目标是一次参加一个连接,每个线程执行一次我的函数doProcess(),并避免其他线程在使用它时运行其他线程。