子线程退出后,导致主线程退出?
在主线程的末尾,我有一段打印的代码:
我执行了代码之后,有时候可以打印出结果,有时候却不可以打印结果:
那么是否和我想的那样,子线程退出会导致主线程退出?
(这个程序是一个压力测试程序,bug有点多)
详细代码如下:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/param.h>
#include <rpc/types.h>
#include <getopt.h>
#include <strings.h>
#include <time.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
int request_nums = 1;
int already_request_nums = 0;
int clients_num = 1;
int thread_nums = 1;
int failed = 0;
int success = 0;
int benchtime = 1; // 默认持续发起请求的时间
int timerexpired = 0; // 是否请求到指定的时间(1表示时间到,0表示没到时间)
int start = 0; //开始/关闭标志
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
const int MAX_LINE = 2048;
const int port = 80;
// 请求行的最大长度
const int request_size = 2048;
char request[request_size];
const int url_max_size = 100;
char url[url_max_size];
// 发起请求
void *bench(void *arg);
// 构造请求行
void build_request(const char *url);
ssize_t readline(int fd, char *vptr, size_t maxlen);
// 返回已经建立连接的套接字
int create_socket (const char *host);
// 设置非阻塞
void setnonblocking(int sock);
void timeover(int sig) {
timerexpired = 1;
}
// 显示错误,并且结束进程
void error_die( const char *sc ) {
perror(sc);
exit(1);
}
/*
作用:设置文件描述符的状态为非阻塞的
参数1:需要修改状态的文件描述符
*/
void setnonblocking(int sock) {
int opts;
opts=fcntl(sock, F_GETFL);
if(opts<0) {
error_die("fcntl(sock,GETFL)");
}
opts = opts | O_NONBLOCK;
if(fcntl(sock, F_SETFL, opts)<0) {
error_die("fcntl(sock,SETFL,opts)");
}
}
void *bench(void *arg) {
int req_len;
int sockfd[clients_num];
char buf[1024];
req_len = strlen(request); // 请求行的长度
// 创建套接字
for (int i = 0; i < clients_num; ++i) {
sockfd[i] = create_socket(url);
if(sockfd[i] < 0) { // 连接服务器失败,所以算一次请求失败
pthread_mutex_lock(&lock);
failed++;
pthread_mutex_unlock(&lock);
continue;
}
}
while(!start) {};
while(1) {
if (timerexpired) { // 时间到了,说明上一次线程在请求连接的过程中可能被打断了,所以不算失败
if (failed > 0) {
pthread_mutex_lock(&lock);
--failed;
pthread_mutex_unlock(&lock);
}
// pthread_exit((void*)0);
}
for (int i = 0; i < clients_num; ++i) {
int n = write(sockfd[i], request, req_len);
if(n < 0) { // 没有一次发送完,也算做一次请求失败
pthread_mutex_lock(&lock);
failed++;
pthread_mutex_unlock(&lock);
continue;
}
int m = read(sockfd[i], buf, 1024);
// printf("%s\n", buf);
memset(buf, '\0', 1024);
if (m > 0) {
pthread_mutex_lock(&lock);
++success;
pthread_mutex_unlock(&lock);
}
}
}
for (int i = 0; i < clients_num; ++i) {
close(sockfd[i]);
}
// pthread_exit((void*)0);
}
// 构造请求头
void build_request(const char *url) {
bzero(request, request_size);
strcpy(request, "GET");
strcat(request, " ");
strcat(request, "/");
strcat(request, " ");
strcat(request, "HTTP/1.1");
strcat(request, "\n");
strcat(request, "host: localhost");
strcat(request, "\n\n");
}
/*readline函数实现*/
ssize_t readline(int fd, char *vptr, size_t maxlen) {
ssize_t n, rc;
char c, *ptr;
ptr = vptr;
for (n = 1; n < maxlen; n++) {
if ( (rc = read(fd, &c,1)) == 1) {
*ptr++ = c;
if (c == '\n')
break; /* newline is stored, like fgets() */
} else if (rc == 0) {
*ptr = 0;
return(n - 1); /* EOF, n - 1 bytes were read */
} else
return(-1); /* error, errno set by read() */
}
*ptr = 0; /* null terminate like fgets() */
return(n);
}
int create_socket (const char *host) {
/*声明套接字和链接服务器地址*/
int sockfd;
struct sockaddr_in servaddr;
/*(1) 创建套接字*/
if((sockfd = socket(AF_INET , SOCK_STREAM , 0)) == -1) {
error_die("socket error");
}
/*(2) 设置链接服务器地址结构*/
bzero(&servaddr , sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port); // 默认为8080端口
if(inet_pton(AF_INET , host , &servaddr.sin_addr) < 0) {
printf("inet_pton error for %s\n", host);
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
return sockfd;
}
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("连接服务器失败");
return -1;
}
return sockfd;
}
int main(int argc, char **argv) {
int ch;
pthread_attr_t attr;
struct sigaction action;
// 解析命令行
while((ch = getopt(argc, argv, "n:c:p:u:")) != -1) {
switch(ch) {
case 'n': // 总的请求数
request_nums = atoi(optarg);
break;
case 'c': // 模拟出的客户端数目
clients_num = atoi(optarg);
break;
case 'p': // 总的线程个数
thread_nums = atoi(optarg);
break;
case 'u': // 目标url
strcpy(url, optarg);
break;
}
}
build_request(url); // 构造请求行
pthread_attr_init(&attr);
//注册信号处理函数
action.sa_handler = timeover;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_t tid[thread_nums];
for (int i = 0; i < thread_nums; ++i) {
/*创建子线程来对服务器进行连接*/
if(pthread_create(&tid[i] , NULL , bench, NULL) == -1) {
perror("pthread create error.\n");
exit(1);
}
}
if(sigaction(SIGALRM, &action, NULL) < 0 ) {
error_die("sigaction:");
}
alarm(benchtime);
start = 1; // 开始
printf("总的请求数%d\n", request_nums);
printf("连接数%d\n", clients_num);
printf("线程数目%d\n", thread_nums);
while(!timerexpired);
printf("失败次数:%d\n", failed);
printf("成功次数:%d\n", success);
pthread_attr_destroy(&attr);
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不会。