[英]Thread ending, ends the entire program?
以下循环位于程序的内部。 它接受传入的连接,并有一个线程可以处理它。
问题是,一旦任何线程终止,它就会终止整个程序。 这是代码:
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#define BUFLEN 1500
#define MAXCON 30
char *returnTimeDate(int inputchoice);
void readWriteToClient(int inputconnfd);
int main(){
int backlog = 10;
int fd;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
// Error: unable to create socket
}
struct sockaddr_in cliaddr;
socklen_t cliaddrlen = sizeof(cliaddr);
struct sockaddr_in addr;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family = AF_INET;
addr.sin_port = htons(5001);
if (bind(fd, (struct sockaddr *) &addr, (socklen_t) sizeof(addr)) == -1) {
fprintf(stderr,"Bind Didn't Work\n");
}
if (listen(fd, backlog) == -1) {
fprintf(stderr,"Listen Didn't Work\n");
}
pthread_t *threadsArray = (pthread_t *)calloc(MAXCON, sizeof(pthread_t));
pthread_t *threadPtr = threadsArray;
int k;
for(k = 0; k < MAXCON; k++){
fprintf(stderr,"Make %d\n",k);
int connfd;
connfd = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);
if (connfd == -1) {
fprintf(stderr,"Accept Didn't Work\n");
}
fprintf(stderr,"Waited\n",k);
pthread_create( &threadPtr, NULL, readWriteToClient, (void *)connfd);
threadPtr++;
}
pthread_t *threadPtrJoin = threadsArray;
for(k = 0; k < MAXCON; k++){
fprintf(stderr,"Join %d\n",k);
pthread_join( *threadPtrJoin, NULL);
threadPtrJoin++;
}
/* readWriteToClient(connfd);*/
close(fd);
return 0;
}
void readWriteToClient(int inputconnfd){
int connfd = inputconnfd;
while(1){
char *dateString = "DATE\r\n";
char *timeString = "TIME\r\n";
char *endString = "end";
char *bufferTime = returnTimeDate(0);
char *bufferDate = returnTimeDate(1);
ssize_t i;
ssize_t rcount;
char buf[BUFLEN];
char *toReturn = (char *)malloc(BUFLEN*sizeof(char));
rcount = read(connfd, buf, BUFLEN);
if((strcmp (buf, dateString)) == 0){
strcpy(toReturn, bufferDate);
}
if((strcmp (buf, timeString)) == 0){
strcpy(toReturn, bufferTime);
}
if((strcmp (buf, endString)) == 0){
goto outside;
}
if (rcount == -1) {
// Error has occurred
printf("Error: rcount -1");
}
/* fprintf(stderr,"I have received = %s\n",buf);*/
if (write(connfd, toReturn, BUFLEN) == -1) {
fprintf(stderr,"I didn't write = %s\n",buf);
}
}
outside: return;
}
char *returnTimeDate(int inputchoice){
time_t timer;
char *bufferTimee = (char *)malloc(25*sizeof(char));
char *bufferDatee = (char *)malloc(25*sizeof(char));
struct tm* tm_info;
time(&timer);
tm_info = localtime(&timer);
strftime(bufferTimee, 25, "%H:%M:%S\n\0", tm_info);
strftime(bufferDatee, 25, "%d:%m:%Y\n\0", tm_info);
if(inputchoice == 0){
return bufferTimee;
}else{
return bufferDatee;
}
}
为什么这样做呢?
使用pthread时有些事情是非常错误的。
首先,我认为您的意思是:
int st = pthread_create(&threadPtr[k], NULL, readWriteToClient, (void *)connfd);
if (st != 0) {
/* handle error */
}
请注意以下几点:
pthread_create()
的返回值存储在st
并处理其错误情况。 &threadPtr[k]
(类型为pthread_t *
),而不是&threadPtr
(类型为pthread_t **
)。 这可能是造成您问题的原因。 但是我的代码存在的主要问题之一是,您通过将readWriteToClient
传递给pthread_create()
来调用未定义的行为。 pthread_create
原型如下:
int pthread_create(pthread_t *restrict,
const pthread_attr_t *restrict,
void *(*start_routine)(void*),
void *restrict arg);
即使将&threadPtr
更改为&threadPtr[k]
,您也可以按以下方式调用它:
int pthread_create(pthread_t *restrict,
const pthread_attr_t *restrict,
void (*start_routine)(int), // oops!
void *restrict arg);
因此, pthread_create()
接受指向一种类型的函数的指针,但是您要向其传递指向另一种类型的函数的指针(C11,6.7.6.3 / 15,重点是我的):
为了使两个函数类型兼容,两者都应指定兼容的返回类型 。 此外,参数类型列表(如果同时存在)应在参数数量和省略号终止符的使用上达成共识; 相应的参数应该具有兼容的类型 。 [...]
指向该函数的指针被隐式转换,并且无论如何都会调用您的函数,但这按照标准(C11,6.3.2.3 / 8,强调我的)是非法的:
可以将指向一种类型的函数的指针转换为指向另一种类型的函数的指针,然后再次返回。 结果应等于原始指针。 如果使用转换后的指针来调用类型与所引用类型不兼容的函数,则该行为是undefined 。
由于您正在调用未定义的行为,因此您无需知道代码在执行后的行为。
另外,请记住,将int
转换为void *
并返回并不能保证不会丢失信息(这是实现定义的),因此请务必谨慎。
如果在启用警告的情况下进行编译 ,您应该在代码中看到其他一些错误, 应该始终这样做。
我敢打赌,您的编译器对不兼容的指针类型发出了一些警告。
我的建议是在编译阶段修正所有警告 。
如果这样做,您会注意到pthread函数的参数必须是指向void的指针,而不是int。
另外,后一个函数必须返回一个指向void的指针,而不仅仅是返回可能导致堆栈混乱的void的指针。
首先,使用连接fds的数组
int connfd[MAXCON];
然后将connfd保存在
connfd[k] = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);
然后,改变
pthread_create( threadPtr, NULL, readWriteToClient, connfd);
与
pthread_create( threadPtr, NULL, readWriteToClient, (void *) &connfd[k]);
并改变
void readWriteToClient(int inputconnfd)
与
void *readWriteToClient(void *inputconnfd)
然后将其分配给本地变量
int connfd = *((int *) inputconnfd);
让我知道是否有效
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.