在主線程的末尾,我有一段打印的代碼:
我執(zhí)行了代碼之后,有時候可以打印出結(jié)果,有時候卻不可以打印結(jié)果:
那么是否和我想的那樣,子線程退出會導致主線程退出?
(這個程序是一個壓力測試程序,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; // 默認持續(xù)發(fā)起請求的時間
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];
// 發(fā)起請求
void *bench(void *arg);
// 構(gòu)造請求行
void build_request(const char *url);
ssize_t readline(int fd, char *vptr, size_t maxlen);
// 返回已經(jīng)建立連接的套接字
int create_socket (const char *host);
// 設置非阻塞
void setnonblocking(int sock);
void timeover(int sig) {
timerexpired = 1;
}
// 顯示錯誤,并且結(jié)束進程
void error_die( const char *sc ) {
perror(sc);
exit(1);
}
/*
作用:設置文件描述符的狀態(tài)為非阻塞的
參數(shù)1:需要修改狀態(tài)的文件描述符
*/
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); // 請求行的長度
// 創(chuàng)建套接字
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) { // 沒有一次發(fā)送完,也算做一次請求失敗
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);
}
// 構(gòu)造請求頭
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函數(shù)實現(xiàn)*/
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) 創(chuàng)建套接字*/
if((sockfd = socket(AF_INET , SOCK_STREAM , 0)) == -1) {
error_die("socket error");
}
/*(2) 設置鏈接服務器地址結(jié)構(gòu)*/
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': // 總的請求數(shù)
request_nums = atoi(optarg);
break;
case 'c': // 模擬出的客戶端數(shù)目
clients_num = atoi(optarg);
break;
case 'p': // 總的線程個數(shù)
thread_nums = atoi(optarg);
break;
case 'u': // 目標url
strcpy(url, optarg);
break;
}
}
build_request(url); // 構(gòu)造請求行
pthread_attr_init(&attr);
//注冊信號處理函數(shù)
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) {
/*創(chuàng)建子線程來對服務器進行連接*/
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("總的請求數(shù)%d\n", request_nums);
printf("連接數(shù)%d\n", clients_num);
printf("線程數(shù)目%d\n", thread_nums);
while(!timerexpired);
printf("失敗次數(shù):%d\n", failed);
printf("成功次數(shù):%d\n", success);
pthread_attr_destroy(&attr);
return 0;
}
北大青鳥APTECH成立于1999年。依托北京大學優(yōu)質(zhì)雄厚的教育資源和背景,秉承“教育改變生活”的發(fā)展理念,致力于培養(yǎng)中國IT技能型緊缺人才,是大數(shù)據(jù)專業(yè)的國家
北大青鳥中博軟件學院創(chuàng)立于2003年,作為華東區(qū)著名互聯(lián)網(wǎng)學院和江蘇省首批服務外包人才培訓基地,中博成功培育了近30000名軟件工程師走向高薪崗位,合作企業(yè)超4
中公教育集團創(chuàng)建于1999年,經(jīng)過二十年潛心發(fā)展,已由一家北大畢業(yè)生自主創(chuàng)業(yè)的信息技術與教育服務機構(gòu),發(fā)展為教育服務業(yè)的綜合性企業(yè)集團,成為集合面授教學培訓、網(wǎng)
達內(nèi)教育集團成立于2002年,是一家由留學海歸創(chuàng)辦的高端職業(yè)教育培訓機構(gòu),是中國一站式人才培養(yǎng)平臺、一站式人才輸送平臺。2014年4月3日在美國成功上市,融資1
曾工作于聯(lián)想擔任系統(tǒng)開發(fā)工程師,曾在博彥科技股份有限公司擔任項目經(jīng)理從事移動互聯(lián)網(wǎng)管理及研發(fā)工作,曾創(chuàng)辦藍懿科技有限責任公司從事總經(jīng)理職務負責iOS教學及管理工作。
浪潮集團項目經(jīng)理。精通Java與.NET 技術, 熟練的跨平臺面向?qū)ο箝_發(fā)經(jīng)驗,技術功底深厚。 授課風格 授課風格清新自然、條理清晰、主次分明、重點難點突出、引人入勝。
精通HTML5和CSS3;Javascript及主流js庫,具有快速界面開發(fā)的能力,對瀏覽器兼容性、前端性能優(yōu)化等有深入理解。精通網(wǎng)頁制作和網(wǎng)頁游戲開發(fā)。
具有10 年的Java 企業(yè)應用開發(fā)經(jīng)驗。曾經(jīng)歷任德國Software AG 技術顧問,美國Dachieve 系統(tǒng)架構(gòu)師,美國AngelEngineers Inc. 系統(tǒng)架構(gòu)師。