├── .gitignore └── CodeInSlides ├── chapter3 ├── Makefile ├── ProcessBasicAPI-fork.c ├── ProcessBasicAPI-races.c ├── ProcessBasicAPI-shell.c ├── ThreadBasicAPI-calcShareData.c └── ThreadBasicAPI-create.c ├── chapter4 ├── ATMProblemShow-mutex.c ├── ATMProblemShow.c ├── BoundedBuffer-monitor-mesatest.c ├── BoundedBuffer-monitor.c ├── BoundedBuffer-mutex.c ├── BoundedBuffer-semaphore.c ├── ConcurrentQuickSort-Iteration.cpp ├── ConcurrentQuickSort-Recursive-broken.c ├── ConcurrentQuickSort-Recursive.c ├── ConcurrentWget-OnDemand.c ├── ConcurrentWget-ThreadPool.c ├── Deadlock.c ├── DynamicAssignJob.c ├── HeteroThreads.c ├── HomoThreads.c ├── Makefile ├── MultiCat.sh ├── PreAssignJob.c ├── Problems-CPUOoO.c ├── Problems-CompilerOptimization-O1.s ├── Problems-CompilerOptimization-O2.s ├── Problems-CompilerOptimization.c ├── Statistics_for_x&y.py └── testUrl.in ├── chapter5 ├── Makefile ├── Measure-ALU-O1.s ├── Measure-ALU-O2.s ├── Measure-ALU-broken-O0.s ├── Measure-ALU-broken-O1.s ├── Measure-ALU-broken-O2.s ├── Measure-ALU-broken-simplified-O0.s ├── Measure-ALU-broken-simplified-O1.s ├── Measure-ALU-broken-simplified-O2.s ├── Measure-ALU-broken-simplified.c ├── Measure-ALU-broken.c ├── Measure-ALU.c ├── Measure-mutex-CTXswitch.c ├── Measure-mutex-syscall.c └── PrintToMonitor.c ├── chapter7 ├── CountResult.sh ├── HighConcurrent-client.c ├── HighConcurrent-epoll-server.c ├── HighConcurrent-normal-server.c ├── Makefile ├── TCP-client-reliable.c ├── TCP-client-thread-recv.c ├── TCP-client-thread-send.c ├── TCP-client.c ├── TCP-server-reliable.c ├── TCP-server-thread-recv.c ├── TCP-server-thread-send.c ├── TCP-server.c ├── UDP-client.c ├── UDP-server.c ├── echo-client.c ├── echo-server.c └── kv.go └── miscellaneous ├── MemLayout.c ├── contextswitch ├── .gitignore ├── COPYING ├── Makefile ├── README ├── cpubench.sh ├── timectxsw.c ├── timectxsw2.c ├── timectxswws.c ├── timesyscall.c ├── timetctxsw.c └── timetctxsw2.c └── multipipe-popen ├── multipipe-popen.c └── testProgram.c /.gitignore: -------------------------------------------------------------------------------- 1 | /CodeInSlides/chapter3/ProcessBasicAPI-fork 2 | /CodeInSlides/chapter3/ThreadBasicAPI-calcShareData 3 | /CodeInSlides/chapter4/ATMProblemShow 4 | /CodeInSlides/chapter4/ATMProblemShow-mutex 5 | /CodeInSlides/chapter4/BoundedBuffer-monitor 6 | /CodeInSlides/chapter4/BoundedBuffer-mutex 7 | /CodeInSlides/chapter4/BoundedBuffer-semaphore 8 | /CodeInSlides/chapter3/ProcessBasicAPI-races 9 | /CodeInSlides/chapter3/ProcessBasicAPI-shell 10 | /CodeInSlides/chapter3/ThreadBasicAPI-create 11 | /CodeInSlides/chapter4/BoundedBuffer-monitor-mesatest 12 | /CodeInSlides/chapter4/Deadlock 13 | /CodeInSlides/chapter4/testInput/*.txt 14 | /CodeInSlides/chapter4/PreAssignJob 15 | /CodeInSlides/chapter4/DynamicAssignJob 16 | /CodeInSlides/chapter4/HomoThreads 17 | /CodeInSlides/chapter4/*.log 18 | /CodeInSlides/chapter4/HeteroThreads 19 | *.html 20 | *.log 21 | /CodeInSlides/chapter4/ConcurrentWget-ThreadPool 22 | /CodeInSlides/chapter4/ConcurrentWget-OnDemand 23 | /CodeInSlides/chapter4/ConcurrentQuickSort-Recursive 24 | /CodeInSlides/chapter4/*.txt 25 | /CodeInSlides/chapter4/ConcurrentQuickSort-Iteration 26 | /CodeInSlides/chapter5/Measure-ALU 27 | /CodeInSlides/chapter5/Measure-ALU-broken 28 | /CodeInSlides/chapter5/Measure-mutex 29 | /CodeInSlides/chapter5/Measure-mutex-CTXswitch 30 | /CodeInSlides/chapter5/Measure-mutex-syscall 31 | /CodeInSlides/chapter5/Measure-ALU-broken-simplified 32 | /CodeInSlides/chapter4/*.data 33 | /CodeInSlides/chapter5/PrintToMonitor 34 | /CodeInSlides/miscellaneous/multipipe-popen/multipipe-popen 35 | /CodeInSlides/miscellaneous/multipipe-popen/testProgram 36 | /CodeInSlides/chapter4/*.old 37 | /CodeInSlides/chapter4/ConcurrentQuickSort-Recursive-broken 38 | /CodeInSlides/chapter7/UDP-client 39 | /CodeInSlides/chapter7/UDP-server 40 | /CodeInSlides/chapter7/TCP-client 41 | /CodeInSlides/chapter7/TCP-server 42 | /CodeInSlides/chapter7/TCP-client-reliable 43 | /CodeInSlides/chapter7/TCP-server-reliable 44 | /CodeInSlides/chapter7/TCP-client-thread-write 45 | /CodeInSlides/chapter7/TCP-server-thread-write 46 | /CodeInSlides/chapter7/TCP-client-thread-recv 47 | /CodeInSlides/chapter7/TCP-server-thread-recv 48 | /CodeInSlides/chapter7/TCP-client-thread-send 49 | /CodeInSlides/chapter7/TCP-server-thread-send 50 | *.DS_Store 51 | -------------------------------------------------------------------------------- /CodeInSlides/chapter3/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010 Benoit Sigoure 2 | # 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program. If not, see . 15 | 16 | CC = gcc 17 | CFLAGS = -O2 -pthread 18 | 19 | # the build target executable: 20 | TARGETS = ProcessBasicAPI-fork ProcessBasicAPI-shell ProcessBasicAPI-races ThreadBasicAPI-create ThreadBasicAPI-calcShareData 21 | 22 | all: $(TARGETS) 23 | 24 | clean: 25 | $(RM) $(TARGETS) 26 | 27 | -------------------------------------------------------------------------------- /CodeInSlides/chapter3/ProcessBasicAPI-fork.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | pid_t cpid, mypid; 11 | int status=0; 12 | pid_t pid = getpid(); /* get current processes PID */ 13 | printf("Parent pid: %d\n", pid); 14 | cpid = fork(); 15 | if (cpid > 0) { /* Parent Process */ 16 | mypid = getpid(); 17 | printf("[%d] parent of [%d]\n", mypid, cpid); 18 | printf("Parent exit\n"); 19 | } else if (cpid == 0) { /* Child Process */ 20 | mypid = getpid(); 21 | printf("[%d] child\n", mypid); 22 | printf("Child exit\n"); 23 | } else { 24 | perror("Fork failed"); 25 | exit(1); 26 | } 27 | exit(0); 28 | } 29 | 30 | // usleep(1000); 31 | // wait(&status); -------------------------------------------------------------------------------- /CodeInSlides/chapter3/ProcessBasicAPI-races.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() 10 | { 11 | int i; 12 | pid_t mypid; 13 | pid_t cpid = fork(); 14 | if (cpid > 0) { 15 | mypid = getpid(); 16 | printf("[%d] parent of [%d]\n", mypid, cpid); 17 | for (i=0; i<10; i++) { 18 | printf("[%d] parent: %d\n", mypid, i); 19 | usleep(1000); 20 | } 21 | } else if (cpid == 0) { 22 | mypid = getpid(); 23 | printf("[%d] child\n", mypid); 24 | for (i=0; i>-10; i--) { 25 | printf("[%d] child: %d\n", mypid, i); 26 | usleep(1000); 27 | } 28 | } 29 | 30 | return 0; 31 | } -------------------------------------------------------------------------------- /CodeInSlides/chapter3/ProcessBasicAPI-shell.c: -------------------------------------------------------------------------------- 1 | // From https://codereview.stackexchange.com/questions/67746/simple-shell-in-c 2 | 3 | // ps --forest -o pid,tty,stat,time,cmd -g pid 4 | // Show child process of pid 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | void parseCmd(char* cmd, char** params); 15 | int executeCmd(char** params); 16 | 17 | #define MAX_COMMAND_LENGTH 100 18 | #define MAX_NUMBER_OF_PARAMS 10 19 | 20 | int main() 21 | { 22 | char cmd[MAX_COMMAND_LENGTH + 1]; 23 | char* params[MAX_NUMBER_OF_PARAMS + 1]; 24 | 25 | int cmdCount = 0; 26 | 27 | while(1) { 28 | // Print command prompt 29 | char* username = getenv("USER"); 30 | printf("%s@shell %d> ", username, ++cmdCount); 31 | 32 | // Read command from standard input, exit on Ctrl+D 33 | if(fgets(cmd, sizeof(cmd), stdin) == NULL) break; 34 | 35 | // Remove trailing newline character, if any 36 | if(cmd[strlen(cmd)-1] == '\n') { 37 | cmd[strlen(cmd)-1] = '\0'; 38 | } 39 | 40 | // Split cmd into array of parameters 41 | parseCmd(cmd, params); 42 | 43 | // Exit? 44 | if(strcmp(params[0], "exit") == 0) break; 45 | 46 | // Execute command 47 | if(executeCmd(params) == 0) break; 48 | } 49 | 50 | return 0; 51 | } 52 | 53 | // Split cmd into array of parameters 54 | void parseCmd(char* cmd, char** params) 55 | { 56 | for(int i = 0; i < MAX_NUMBER_OF_PARAMS; i++) { 57 | params[i] = strsep(&cmd, " "); 58 | if(params[i] == NULL) break; 59 | } 60 | } 61 | 62 | int executeCmd(char** params) 63 | { 64 | // Fork process 65 | pid_t pid = fork(); 66 | 67 | // Error 68 | if (pid == -1) { 69 | char* error = strerror(errno); 70 | printf("fork: %s\n", error); 71 | return 1; 72 | } 73 | 74 | // Child process 75 | else if (pid == 0) { 76 | // Execute command 77 | execvp(params[0], params); 78 | 79 | // Error occurred 80 | char* error = strerror(errno); 81 | printf("shell: %s: %s\n", params[0], error); 82 | return 0; 83 | } 84 | 85 | // Parent process 86 | else { 87 | // Wait for child process to finish 88 | int childStatus; 89 | waitpid(pid, &childStatus, 0); 90 | return 1; 91 | } 92 | } -------------------------------------------------------------------------------- /CodeInSlides/chapter3/ThreadBasicAPI-calcShareData.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define NUM_ARR_SIZE 5000 9 | 10 | int num[NUM_ARR_SIZE]; 11 | 12 | void* calcSum1(void* args) { 13 | int sum=0; 14 | for(int i=0;i<2500;i++) 15 | sum=sum+num[i]; 16 | pthread_t tid = pthread_self(); 17 | printf("[%ld] worker thread: \t %d\n", pthread_self(), sum); 18 | } 19 | 20 | void* calcSum2(void* args) { 21 | int sum=0; 22 | for(int i=2500;ifirst; 69 | // int last=para->last; 70 | // int sum=0; 71 | // for(int i=first;iresult=sum; 80 | // } 81 | 82 | 83 | // int main(int argc, char *argv[]) 84 | // { 85 | // int numOfWorkerThread=1; 86 | // if(argc>=2) 87 | // numOfWorkerThread=atoi(argv[1]); 88 | // if(numOfWorkerThread>NUM_ARR_SIZE) 89 | // numOfWorkerThread=NUM_ARR_SIZE; 90 | 91 | // for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void* myfunc(void* args) { 9 | pthread_t tid = pthread_self(); 10 | printf("[%ld] child. Exit\n", tid); 11 | } 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | 16 | pthread_t th; 17 | if(pthread_create(&th, NULL, myfunc, NULL)!=0) 18 | { 19 | perror("pthread_create failed"); 20 | exit(1); 21 | } 22 | 23 | pthread_t mytid = pthread_self(); 24 | 25 | printf("Parent tid: %ld\n", mytid); 26 | printf("[%ld] parent of [%ld]. Exit\n", mytid, th); 27 | 28 | // pthread_join(th, NULL); 29 | 30 | exit(0); 31 | } -------------------------------------------------------------------------------- /CodeInSlides/chapter4/ATMProblemShow-mutex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define TEST_ITERATIONS 1000 9 | 10 | int accountBalance=0; 11 | int amount=10; 12 | 13 | pthread_mutex_t accountBalanceLock; 14 | 15 | void* threadDeposit(void* args) { 16 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define TEST_ITERATIONS 1000 9 | 10 | int accountBalance=0; 11 | int amount=10; 12 | 13 | void* threadDeposit(void* args) { 14 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define IF_PRINT_DEBUG 0 9 | #define BUF_CAPACITY 10 10 | 11 | int producerNum=1; 12 | int consumerNum=1; 13 | int TEST_COKE_NUM=100000; 14 | 15 | int bufSize=0; 16 | 17 | pthread_mutex_t mutex; 18 | pthread_cond_t cndFull; 19 | pthread_cond_t cndEmpty; 20 | 21 | void* Producer(void* args) { 22 | for(int i=0;iBUF_CAPACITY) 34 | fprintf(stderr,"[%ld] producer: OVERFLOW! enqueue a coke, bufSize %d\n",pthread_self(),bufSize); 35 | if(IF_PRINT_DEBUG) 36 | printf("[%ld] producer: enqueue a coke, bufSize %d\n",pthread_self(),bufSize); 37 | if(IF_PRINT_DEBUG) 38 | printf("[%ld] producer: wakeup waiting consumers\n",pthread_self()); 39 | pthread_cond_broadcast(&cndEmpty); 40 | pthread_mutex_unlock(&mutex); 41 | } 42 | } 43 | 44 | void* Consumer(void* args) { 45 | for(int i=0;i=3) 70 | { 71 | producerNum=atoi(argv[1]); 72 | consumerNum=atoi(argv[2]); 73 | } 74 | if(argc>=4) 75 | { 76 | TEST_COKE_NUM=atoi(argv[3]); 77 | } 78 | 79 | pthread_cond_init(&cndFull,NULL); 80 | pthread_cond_init(&cndEmpty,NULL); 81 | pthread_mutex_init(&mutex,NULL); 82 | 83 | printf("Before run: \t\t coke_num \t\t %d\n", bufSize); 84 | 85 | pthread_t th1[producerNum]; 86 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define IF_PRINT_DEBUG 0 9 | #define BUF_CAPACITY 10 10 | 11 | int producerNum=1; 12 | int consumerNum=1; 13 | int TEST_COKE_NUM=100000; 14 | 15 | int bufSize=0; 16 | 17 | pthread_mutex_t mutex; 18 | pthread_cond_t cndFull; 19 | pthread_cond_t cndEmpty; 20 | 21 | void* Producer(void* args) { 22 | for(int i=0;i=3) 66 | { 67 | producerNum=atoi(argv[1]); 68 | consumerNum=atoi(argv[2]); 69 | } 70 | if(argc>=4) 71 | { 72 | TEST_COKE_NUM=atoi(argv[3]); 73 | } 74 | 75 | pthread_cond_init(&cndFull,NULL); 76 | pthread_cond_init(&cndEmpty,NULL); 77 | pthread_mutex_init(&mutex,NULL); 78 | 79 | printf("Before run: \t\t coke_num \t\t %d\n", bufSize); 80 | 81 | pthread_t th1[producerNum]; 82 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define IF_PRINT_DEBUG 0 9 | #define BUF_CAPACITY 10 10 | 11 | int producerNum=1; 12 | int consumerNum=1; 13 | int TEST_COKE_NUM=100000; 14 | 15 | int bufSize=0; 16 | 17 | pthread_mutex_t mutex; 18 | 19 | void* Producer(void* args) { 20 | for(int i=0;i=3) 62 | { 63 | producerNum=atoi(argv[1]); 64 | consumerNum=atoi(argv[2]); 65 | } 66 | if(argc>=4) 67 | { 68 | TEST_COKE_NUM=atoi(argv[3]); 69 | } 70 | 71 | pthread_mutex_init(&mutex,NULL); 72 | 73 | printf("Before run: \t\t coke_num \t\t %d\n", bufSize); 74 | 75 | pthread_t th1[producerNum]; 76 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define IF_PRINT_DEBUG 0 10 | #define BUF_CAPACITY 10 11 | 12 | int producerNum=1; 13 | int consumerNum=1; 14 | int TEST_COKE_NUM=100000; 15 | 16 | int bufSize=0; 17 | 18 | sem_t fullSlots; 19 | sem_t emptySlots; 20 | pthread_mutex_t mutex; 21 | 22 | void* Producer(void* args) { 23 | for(int i=0;i=3) 55 | { 56 | producerNum=atoi(argv[1]); 57 | consumerNum=atoi(argv[2]); 58 | } 59 | if(argc>=4) 60 | { 61 | TEST_COKE_NUM=atoi(argv[3]); 62 | } 63 | 64 | sem_init(&fullSlots, 0, 0); 65 | sem_init(&emptySlots, 0, BUF_CAPACITY); 66 | pthread_mutex_init(&mutex,NULL); 67 | 68 | printf("Before run: \t\t coke_num \t\t %d\n", bufSize); 69 | 70 | pthread_t th1[producerNum]; 71 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define IF_PRINT_DEBUG 0 15 | #define CONCURRENT_THREAD_NUM 4 16 | #define MIN_ARRAY_LEN_FOR_CREATE_A_THREAD_TO_SORT 100000 17 | 18 | typedef struct { 19 | int* array; 20 | int left; 21 | int right; 22 | } SortJob; 23 | 24 | std::stack sortJobStackGlobal; 25 | pthread_mutex_t sortJobStackMutex=PTHREAD_MUTEX_INITIALIZER; 26 | sem_t sortJobStackEmptySlots; 27 | int ifThreadBusy[CONCURRENT_THREAD_NUM]; 28 | //ifThreadBusy[i] indicates if a thread is doing sorting job 29 | //If all ifThreadBusy[i]==0, then the whole sort has finished and we can exit 30 | int ifAllThreadExit;//Flag for main thread to notify worker exit 31 | 32 | double time_diff(struct timeval x , struct timeval y); 33 | void swap(int* array,int first,int second); 34 | int PartSort(int* array,int left,int right); 35 | void* QuickSortParallel(void* args); 36 | void QuickSortSequential(int* array, int left, int right); 37 | int createAThreadToQuickSort(int *array, int left, int right, pthread_t *th); 38 | 39 | void initParallelSort(int *array, int sortArrayLen) 40 | { 41 | SortJob job; 42 | job.array=array; 43 | job.left=0; 44 | job.right=sortArrayLen-1; 45 | sortJobStackGlobal.push(job); 46 | for(int i=0;i= array[key]) 87 | --right; 88 | swap(array,left,right); 89 | } 90 | swap(array,left,key); 91 | return left; 92 | } 93 | 94 | void* QuickSortParallel(void* args) 95 | { 96 | int *threadID=(int *) args; 97 | if(IF_PRINT_DEBUG==2) 98 | printf("Thread[%d] start.\n",*threadID); 99 | SortJob job; 100 | while(1) 101 | { 102 | sem_wait(&sortJobStackEmptySlots); 103 | pthread_mutex_lock(&sortJobStackMutex); 104 | if(ifAllThreadExit==1) { 105 | if(IF_PRINT_DEBUG==2) 106 | printf("Thread[%d] exit.\n",*threadID); 107 | pthread_mutex_unlock(&sortJobStackMutex); 108 | break; 109 | } 110 | job = sortJobStackGlobal.top(); 111 | sortJobStackGlobal.pop(); 112 | int left=job.left; 113 | int right=job.right; 114 | ifThreadBusy[*threadID]=1; 115 | pthread_mutex_unlock(&sortJobStackMutex); 116 | if(right-left>=MIN_ARRAY_LEN_FOR_CREATE_A_THREAD_TO_SORT) 117 | { 118 | int index = PartSort(job.array,left,right); 119 | if(IF_PRINT_DEBUG==2) 120 | printf("Thread[%d]: PartSort[%d-%d] ifThreadBusy=%d\n" 121 | ,*threadID,job.left,job.right,ifThreadBusy[*threadID]); 122 | pthread_mutex_lock(&sortJobStackMutex); 123 | if((index - 1) > left)//左子序列 124 | { 125 | job.left=left; 126 | job.right=index - 1; 127 | sortJobStackGlobal.push(job); 128 | sem_post(&sortJobStackEmptySlots); 129 | if(IF_PRINT_DEBUG==2) 130 | printf("Thread[%d]: push[%d-%d] ifThreadBusy=%d\n" 131 | ,*threadID,job.left,job.right,ifThreadBusy[*threadID]); 132 | } 133 | if((index + 1) < right)//右子序列 134 | { 135 | job.left=index + 1; 136 | job.right=right; 137 | sortJobStackGlobal.push(job); 138 | sem_post(&sortJobStackEmptySlots); 139 | if(IF_PRINT_DEBUG==2) 140 | printf("Thread[%d]: push[%d-%d] ifThreadBusy=%d\n" 141 | ,*threadID,job.left,job.right,ifThreadBusy[*threadID]); 142 | } 143 | ifThreadBusy[*threadID]=0; 144 | pthread_mutex_unlock(&sortJobStackMutex); 145 | } 146 | else 147 | { 148 | if(IF_PRINT_DEBUG==2) 149 | printf("Thread[%d]: QuickSortSequential[%d-%d] ifThreadBusy=%d\n" 150 | ,*threadID,job.left,job.right,ifThreadBusy[*threadID]); 151 | QuickSortSequential(job.array,left,right); 152 | pthread_mutex_lock(&sortJobStackMutex); 153 | ifThreadBusy[*threadID]=0; 154 | pthread_mutex_unlock(&sortJobStackMutex); 155 | } 156 | } 157 | } 158 | 159 | void QuickSortSequential(int* array, int left, int right) 160 | { 161 | SortJob job; 162 | job.array=array; 163 | job.left=left; 164 | job.right=right; 165 | std::stack sortJobStack; 166 | sortJobStack.push(job); 167 | while(1) 168 | { 169 | if(sortJobStack.empty()) 170 | break; 171 | job = sortJobStack.top(); 172 | sortJobStack.pop(); 173 | int left=job.left; 174 | int right=job.right; 175 | 176 | int index = PartSort(job.array,job.left,job.right); 177 | if((index - 1) > left)//左子序列 178 | { 179 | job.left=left; 180 | job.right=index - 1; 181 | sortJobStack.push(job); 182 | } 183 | if((index + 1) < right)//右子序列 184 | { 185 | job.left=index + 1; 186 | job.right=right; 187 | sortJobStack.push(job); 188 | } 189 | } 190 | } 191 | 192 | void waitSortDoneAndNotifyAllThreadsToExit() 193 | { 194 | while(1) 195 | { 196 | usleep(10000);//Check every 10ms 197 | pthread_mutex_lock(&sortJobStackMutex); 198 | if(sortJobStackGlobal.empty()) 199 | { 200 | int exit=1; 201 | for(int i=0;i=2) 291 | sortArrayLen=atoi(argv[1]); 292 | int sortTimes=1; 293 | if(argc>=3) 294 | sortTimes=atoi(argv[2]); 295 | 296 | srand(time(NULL)); 297 | 298 | doSortTest(sortArrayLen,sortTimes,1);//Sequential sort 299 | doSortTest(sortArrayLen,sortTimes,0);//Parallel sort 300 | 301 | return 0; 302 | } 303 | 304 | -------------------------------------------------------------------------------- /CodeInSlides/chapter4/ConcurrentQuickSort-Recursive-broken.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define IF_PRINT_DEBUG 0 12 | 13 | int concurrentThreadNum=0; 14 | int maxConcurrentThreadNumEverAppeared=0; 15 | int totalThreadCreated=0; 16 | 17 | pthread_mutex_t threadNumMutex=PTHREAD_MUTEX_INITIALIZER; 18 | // To strictly limit the concurrent thread num, we should use this mutex 19 | // However, this may hurt performance a little. 20 | // As such, you can delete this mutex. 21 | // If so, the concurrent thread num may exceed the limit a little, but not affect the correctness 22 | 23 | double time_diff(struct timeval x , struct timeval y); 24 | void swap(int* array,int first,int second); 25 | int PartSort(int* array,int left,int right); 26 | void* QuickSortParallel(void* args); 27 | void QuickSortSequential(int* array, int left, int right); 28 | int createAThreadToQuickSort(int *array, int left, int right, pthread_t *th); 29 | 30 | 31 | double time_diff(struct timeval x , struct timeval y) 32 | { 33 | double x_ms , y_ms , diff; 34 | x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; 35 | y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; 36 | diff = (double)y_ms - (double)x_ms; 37 | if(diff<0) 38 | { 39 | fprintf(stderr, "ERROR! time_diff<0\n"); 40 | exit(1); 41 | } 42 | return diff; 43 | } 44 | 45 | void swap(int* array,int first,int second) 46 | { 47 | int tmp; 48 | tmp=array[first]; 49 | array[first]=array[second]; 50 | array[second]=tmp; 51 | } 52 | 53 | //左右指针法 54 | int PartSort(int* array,int left,int right) 55 | { 56 | int key = right; 57 | while(left < right) 58 | { 59 | while(left < right && array[left] <= array[key]) 60 | ++left; 61 | while(left < right && array[right] >= array[key]) 62 | --right; 63 | swap(array,left,right); 64 | } 65 | swap(array,left,key); 66 | return left; 67 | } 68 | 69 | typedef struct { 70 | int* array; 71 | int left; 72 | int right; 73 | } SortArgs; 74 | 75 | void* QuickSortParallel(void* args) 76 | { 77 | SortArgs* para = (SortArgs*) args; 78 | int *array=para->array; 79 | int left=para->left; 80 | int right=para->right; 81 | free(para); 82 | 83 | if(left >= right) 84 | return NULL; 85 | 86 | int index = PartSort(array,left,right); 87 | 88 | pthread_t th1; 89 | int re1=createAThreadToQuickSort(array,left,index-1,&th1); 90 | pthread_t th2; 91 | int re2=createAThreadToQuickSort(array,index+1,right,&th2); 92 | if(re1==1) { 93 | pthread_join(th1, NULL); 94 | pthread_mutex_lock(&threadNumMutex); 95 | concurrentThreadNum--; 96 | pthread_mutex_unlock(&threadNumMutex); 97 | } 98 | if(re2==1) { 99 | pthread_join(th2, NULL); 100 | pthread_mutex_lock(&threadNumMutex); 101 | concurrentThreadNum--; 102 | pthread_mutex_unlock(&threadNumMutex); 103 | } 104 | } 105 | 106 | void QuickSortSequential(int* array, int left, int right) 107 | { 108 | if(left >= right) 109 | return; 110 | 111 | int index = PartSort(array,left,right); 112 | 113 | QuickSortSequential(array,left,index-1); 114 | QuickSortSequential(array,index+1,right); 115 | } 116 | 117 | void* QuickSortSequentialThread(void* args) 118 | { 119 | SortArgs* para = (SortArgs*) args; 120 | int *array=para->array; 121 | int left=para->left; 122 | int right=para->right; 123 | free(para); 124 | 125 | // printf("QuickSortSequentialThread: left %d, right %d\n",left,right); 126 | 127 | if(left >= right) 128 | return NULL; 129 | 130 | int index = PartSort(array,left,right); 131 | 132 | QuickSortSequential(array,left,index-1); 133 | QuickSortSequential(array,index+1,right); 134 | } 135 | 136 | 137 | //Do not create thread if there are too many concurrent threads 138 | //Return 1 if create new thread, else return 0 139 | int createAThreadToQuickSort(int *array, int left, int right, pthread_t *th) 140 | { 141 | int re=0; 142 | 143 | SortArgs *sortPara = malloc(sizeof(SortArgs)); 144 | sortPara->array=array; 145 | sortPara->left=left; 146 | sortPara->right=right; 147 | if(pthread_create(th, NULL, QuickSortParallel, sortPara)!=0) 148 | // if(pthread_create(th, NULL, QuickSortSequentialThread, sortPara)!=0) 149 | { 150 | //Cannot create thread, sort sequentially 151 | QuickSortSequential(array,left,right); 152 | re=0; 153 | } 154 | else 155 | { 156 | //Create a thread, return 1 so the outer function will wait me 157 | re=1; 158 | } 159 | return re; 160 | } 161 | 162 | void doSortTest(int sortArrayLen, int runTimes, int ifSequential)//ifSequential 0 for parallel version, else for sequential version 163 | { 164 | int *array=malloc(sizeof(array[0])*sortArrayLen); 165 | 166 | double totalSortTime=0; 167 | for(int n=0;narray=array; 190 | sortPara->left=0; 191 | sortPara->right=sortArrayLen-1; 192 | QuickSortParallel(sortPara); 193 | printf("RUN[%d] Parallel sort done. ",n); 194 | } 195 | else { 196 | QuickSortSequential(array,0,sortArrayLen-1); 197 | printf("RUN[%d] Sequential sort done. ",n); 198 | } 199 | gettimeofday(&tvEnd,NULL); 200 | totalSortTime=totalSortTime+time_diff(tvStart,tvEnd); 201 | printf("Spend %.5lf s.\n",time_diff(tvStart,tvEnd)/1E6); 202 | if(IF_PRINT_DEBUG) 203 | { 204 | printf("RUN[%d] Sorted:\n",n); 205 | for(int i=0;i=2) 225 | sortArrayLen=atoi(argv[1]); 226 | int sortTimes=1; 227 | if(argc>=3) 228 | sortTimes=atoi(argv[2]); 229 | 230 | srand(time(NULL)); 231 | 232 | doSortTest(sortArrayLen,sortTimes,1);//Sequential sort 233 | doSortTest(sortArrayLen,sortTimes,0);//Parallel sort 234 | 235 | return 0; 236 | } 237 | 238 | -------------------------------------------------------------------------------- /CodeInSlides/chapter4/ConcurrentQuickSort-Recursive.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define IF_PRINT_DEBUG 0 12 | 13 | #define MIN_ARRAY_LEN_FOR_CREATE_A_THREAD_TO_SORT 100000 14 | #define MAX_CONCURRENT_THREAD_NUM 1000 15 | int concurrentThreadNum=0; 16 | int maxConcurrentThreadNumEverAppeared=0; 17 | int totalThreadCreated=0; 18 | 19 | pthread_mutex_t threadNumMutex=PTHREAD_MUTEX_INITIALIZER; 20 | // To strictly limit the concurrent thread num, we should use this mutex 21 | // However, this may hurt performance a little. 22 | // As such, you can delete this mutex. 23 | // If so, the concurrent thread num may exceed the limit a little, but not affect the correctness 24 | 25 | double time_diff(struct timeval x , struct timeval y); 26 | void swap(int* array,int first,int second); 27 | int PartSort(int* array,int left,int right); 28 | void* QuickSortParallel(void* args); 29 | void QuickSortSequential(int* array, int left, int right); 30 | int createAThreadToQuickSort(int *array, int left, int right, pthread_t *th); 31 | 32 | 33 | double time_diff(struct timeval x , struct timeval y) 34 | { 35 | double x_ms , y_ms , diff; 36 | x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; 37 | y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; 38 | diff = (double)y_ms - (double)x_ms; 39 | if(diff<0) 40 | { 41 | fprintf(stderr, "ERROR! time_diff<0\n"); 42 | exit(1); 43 | } 44 | return diff; 45 | } 46 | 47 | void swap(int* array,int first,int second) 48 | { 49 | int tmp; 50 | tmp=array[first]; 51 | array[first]=array[second]; 52 | array[second]=tmp; 53 | } 54 | 55 | //左右指针法 56 | int PartSort(int* array,int left,int right) 57 | { 58 | int key = right; 59 | while(left < right) 60 | { 61 | while(left < right && array[left] <= array[key]) 62 | ++left; 63 | while(left < right && array[right] >= array[key]) 64 | --right; 65 | swap(array,left,right); 66 | } 67 | swap(array,left,key); 68 | return left; 69 | } 70 | 71 | typedef struct { 72 | int* array; 73 | int left; 74 | int right; 75 | } SortArgs; 76 | 77 | void* QuickSortParallel(void* args) 78 | { 79 | SortArgs* para = (SortArgs*) args; 80 | int *array=para->array; 81 | int left=para->left; 82 | int right=para->right; 83 | free(para); 84 | 85 | if(left >= right) 86 | return NULL; 87 | 88 | int index = PartSort(array,left,right); 89 | 90 | pthread_t th1; 91 | int re1=createAThreadToQuickSort(array,left,index-1,&th1); 92 | pthread_t th2; 93 | int re2=createAThreadToQuickSort(array,index+1,right,&th2); 94 | if(re1==1) { 95 | pthread_join(th1, NULL); 96 | pthread_mutex_lock(&threadNumMutex); 97 | concurrentThreadNum--; 98 | pthread_mutex_unlock(&threadNumMutex); 99 | } 100 | if(re2==1) { 101 | pthread_join(th2, NULL); 102 | pthread_mutex_lock(&threadNumMutex); 103 | concurrentThreadNum--; 104 | pthread_mutex_unlock(&threadNumMutex); 105 | } 106 | } 107 | 108 | void QuickSortSequential(int* array, int left, int right) 109 | { 110 | if(left >= right) 111 | return; 112 | 113 | int index = PartSort(array,left,right); 114 | 115 | QuickSortSequential(array,left,index-1); 116 | QuickSortSequential(array,index+1,right); 117 | } 118 | 119 | //Do not create thread if there are too many concurrent threads 120 | //Return 1 if create new thread, else return 0 121 | int createAThreadToQuickSort(int *array, int left, int right, pthread_t *th) 122 | { 123 | int re=0; 124 | pthread_mutex_lock(&threadNumMutex); 125 | if(concurrentThreadNum=MIN_ARRAY_LEN_FOR_CREATE_A_THREAD_TO_SORT) 127 | { 128 | totalThreadCreated++; 129 | concurrentThreadNum++; 130 | if(concurrentThreadNum>maxConcurrentThreadNumEverAppeared) 131 | maxConcurrentThreadNumEverAppeared=concurrentThreadNum; 132 | if(IF_PRINT_DEBUG) 133 | printf("Create thread [%d] to sort[%d-%d]\n",totalThreadCreated,left,right); 134 | pthread_mutex_unlock(&threadNumMutex); 135 | 136 | SortArgs *sortPara = malloc(sizeof(SortArgs)); 137 | sortPara->array=array; 138 | sortPara->left=left; 139 | sortPara->right=right; 140 | if(pthread_create(th, NULL, QuickSortParallel, sortPara)!=0) 141 | { 142 | perror("pthread_create failed"); 143 | exit(1); 144 | } 145 | re=1; 146 | } 147 | else 148 | { 149 | pthread_mutex_unlock(&threadNumMutex); 150 | QuickSortSequential(array,left,right); 151 | } 152 | return re; 153 | } 154 | 155 | void doSortTest(int sortArrayLen, int runTimes, int ifSequential)//ifSequential 0 for parallel version, else for sequential version 156 | { 157 | int *array=malloc(sizeof(array[0])*sortArrayLen); 158 | 159 | double totalSortTime=0; 160 | for(int n=0;narray=array; 183 | sortPara->left=0; 184 | sortPara->right=sortArrayLen-1; 185 | QuickSortParallel(sortPara); 186 | printf("RUN[%d] Parallel sort done. Create %d threads in total. The max concurrency ever appeared is %d. " 187 | ,n,totalThreadCreated,maxConcurrentThreadNumEverAppeared); 188 | } 189 | else { 190 | QuickSortSequential(array,0,sortArrayLen-1); 191 | printf("RUN[%d] Sequential sort done. ",n); 192 | } 193 | gettimeofday(&tvEnd,NULL); 194 | totalSortTime=totalSortTime+time_diff(tvStart,tvEnd); 195 | printf("Spend %.5lf s.\n",time_diff(tvStart,tvEnd)/1E6); 196 | if(IF_PRINT_DEBUG) 197 | { 198 | printf("RUN[%d] Sorted:\n",n); 199 | for(int i=0;i=2) 219 | sortArrayLen=atoi(argv[1]); 220 | int sortTimes=1; 221 | if(argc>=3) 222 | sortTimes=atoi(argv[2]); 223 | 224 | srand(time(NULL)); 225 | 226 | doSortTest(sortArrayLen,sortTimes,1);//Sequential sort 227 | doSortTest(sortArrayLen,sortTimes,0);//Parallel sort 228 | 229 | return 0; 230 | } 231 | 232 | -------------------------------------------------------------------------------- /CodeInSlides/chapter4/ConcurrentWget-OnDemand.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define MAX_CONCURRENT_INPUT_NUM 10000 13 | #define MAX_URL_LENGTH 1024 14 | 15 | #define OUTPUT_FOLDER_NAME "testOutput" 16 | 17 | long int totalNumOfJobsDone=0; 18 | int totalThreadsCreated=0; 19 | int concurrentThreadsNow=0; 20 | int maxConcurrentThreads=0; 21 | pthread_mutex_t counterMutex=PTHREAD_MUTEX_INITIALIZER; 22 | 23 | double time_diff(struct timeval x , struct timeval y) 24 | { 25 | double x_ms , y_ms , diff; 26 | x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; 27 | y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; 28 | diff = (double)y_ms - (double)x_ms; 29 | if(diff<0) 30 | { 31 | fprintf(stderr, "ERROR! time_diff<0\n"); 32 | exit(1); 33 | } 34 | return diff; 35 | } 36 | 37 | void initOutputFolder() 38 | { 39 | char command[1000]; 40 | sprintf(command,"rm -rf %s",OUTPUT_FOLDER_NAME); 41 | int status=system(command); 42 | mkdir(OUTPUT_FOLDER_NAME, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 43 | } 44 | 45 | typedef struct { 46 | char *job; 47 | long int jobID; 48 | } ThreadParas; 49 | 50 | void* processJobsOnDemandThread(void* args) { 51 | pthread_mutex_lock(&counterMutex); 52 | totalThreadsCreated++; 53 | concurrentThreadsNow++; 54 | if(concurrentThreadsNow>maxConcurrentThreads) 55 | maxConcurrentThreads=concurrentThreadsNow; 56 | pthread_mutex_unlock(&counterMutex); 57 | ThreadParas* para = (ThreadParas*) args; 58 | char *job=para->job; 59 | long int jobID=para->jobID; 60 | 61 | struct timeval tvStart,tvEnd; 62 | gettimeofday(&tvStart,NULL); 63 | char command[MAX_URL_LENGTH+1000]; 64 | memset(command,0,(MAX_URL_LENGTH+1000)*sizeof(command[0])); 65 | sprintf(command,"wget %s -O %s/%05ld.html > %s/%05ld.log 2>&1",job,OUTPUT_FOLDER_NAME,jobID,OUTPUT_FOLDER_NAME,jobID); 66 | // printf("thread[%ld]: %s\n",jobID,command); 67 | int status=system(command);//get the URL page 68 | 69 | //Log time spent 70 | gettimeofday(&tvEnd,NULL); 71 | memset(command,0,(MAX_URL_LENGTH+1000)*sizeof(command[0])); 72 | sprintf(command,"echo \"[RESULT]: get URL %s , spend %.3lf s\" >> %s/%05ld.log" 73 | ,job,time_diff(tvStart,tvEnd)/1E6,OUTPUT_FOLDER_NAME,jobID); 74 | status=system(command); 75 | 76 | free(job); 77 | free(para); 78 | pthread_mutex_lock(&counterMutex); 79 | totalNumOfJobsDone++; 80 | concurrentThreadsNow--; 81 | pthread_mutex_unlock(&counterMutex); 82 | } 83 | 84 | void waitForAllJobsDone(int finalJobID) 85 | { 86 | //Lazily wait all the worker threads finish their wget jobs 87 | while(1) 88 | { 89 | usleep(10000);//Check per 10 ms 90 | pthread_mutex_lock(&counterMutex); 91 | if(totalNumOfJobsDone==finalJobID)//All jobs done 92 | { 93 | pthread_mutex_unlock(&counterMutex); 94 | break; 95 | } 96 | pthread_mutex_unlock(&counterMutex); 97 | } 98 | } 99 | 100 | int main(int argc, char *argv[]) 101 | { 102 | initOutputFolder(); 103 | printf("Start to wget urls ...\n"); 104 | 105 | long int nextJobID=0; 106 | ThreadParas *thPara; 107 | while(1) 108 | { 109 | thPara=malloc(sizeof(ThreadParas)); 110 | thPara->job=malloc(MAX_URL_LENGTH*sizeof(thPara->job[0])); 111 | memset(thPara->job,0,MAX_URL_LENGTH*sizeof(thPara->job[0])); 112 | if(scanf("%s",thPara->job)==EOF) 113 | break; 114 | thPara->jobID=nextJobID; 115 | nextJobID++; 116 | pthread_t th; 117 | if(pthread_create(&th, NULL, processJobsOnDemandThread, thPara)!=0) 118 | { 119 | perror("pthread_create failed"); 120 | exit(1); 121 | } 122 | } 123 | 124 | waitForAllJobsDone(nextJobID); 125 | printf("Finish all jobs! Get %ld URLs in total!\n",totalNumOfJobsDone); 126 | printf("Create %d on-demand threads in total. There are %d max concurrent threads!\n" 127 | ,totalThreadsCreated,maxConcurrentThreads); 128 | //In real project, do free the memory and destroy mutexes and semaphores 129 | exit(0); 130 | } -------------------------------------------------------------------------------- /CodeInSlides/chapter4/ConcurrentWget-ThreadPool.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define MAX_CONCURRENT_INPUT_NUM 10000 13 | #define MAX_URL_LENGTH 1024 14 | 15 | #define OUTPUT_FOLDER_NAME "testOutput" 16 | 17 | long int totalNumOfJobsDone=0; 18 | pthread_mutex_t jobNumMutex=PTHREAD_MUTEX_INITIALIZER; 19 | 20 | double time_diff(struct timeval x , struct timeval y) 21 | { 22 | double x_ms , y_ms , diff; 23 | x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; 24 | y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; 25 | diff = (double)y_ms - (double)x_ms; 26 | if(diff<0) 27 | { 28 | fprintf(stderr, "ERROR! time_diff<0\n"); 29 | exit(1); 30 | } 31 | return diff; 32 | } 33 | 34 | typedef unsigned char BYTE; 35 | int *threadFlags; 36 | 37 | typedef struct { 38 | char **jobs; 39 | int head; 40 | int tail; 41 | long int inCount; 42 | long int outCount; 43 | pthread_mutex_t mutex; 44 | sem_t fullSlots; 45 | sem_t emptySlots; 46 | int queueCapacity; 47 | } JobQueue; 48 | 49 | JobQueue inJobQueue; 50 | 51 | void initJobQueue() 52 | { 53 | inJobQueue.jobs=malloc(MAX_CONCURRENT_INPUT_NUM*sizeof(inJobQueue.jobs[0])); 54 | for(int i=0;i %s/%05ld.log 2>&1",job,OUTPUT_FOLDER_NAME,jobID,OUTPUT_FOLDER_NAME,jobID); 113 | // printf("thread[%d]: %s\n",*id,command); 114 | int status=system(command);//get the URL page 115 | 116 | //Log time spent 117 | gettimeofday(&tvEnd,NULL); 118 | memset(command,0,(MAX_URL_LENGTH+1000)*sizeof(command[0])); 119 | sprintf(command,"echo \"[RESULT]: get URL %s , spend %.3lf s\" >> %s/%05ld.log" 120 | ,job,time_diff(tvStart,tvEnd)/1E6,OUTPUT_FOLDER_NAME,jobID); 121 | status=system(command); 122 | 123 | pthread_mutex_lock(&jobNumMutex); 124 | totalNumOfJobsDone++; 125 | pthread_mutex_unlock(&jobNumMutex); 126 | } 127 | } 128 | 129 | void waitForAllJobsDone(int finalJobID) 130 | { 131 | //Lazily wait all the worker threads finish their wget jobs 132 | while(1) 133 | { 134 | usleep(10000);//Check per 10 ms 135 | pthread_mutex_lock(&jobNumMutex); 136 | if(totalNumOfJobsDone==finalJobID)//All jobs done 137 | { 138 | pthread_mutex_unlock(&jobNumMutex); 139 | break; 140 | } 141 | pthread_mutex_unlock(&jobNumMutex); 142 | } 143 | } 144 | 145 | int main(int argc, char *argv[]) 146 | { 147 | int numOfWorkerThread=1; 148 | if(argc>=2) 149 | numOfWorkerThread=atoi(argv[1]); 150 | 151 | initJobQueue(); 152 | initOutputFolder(); 153 | 154 | printf("Start to wget urls ...\n"); 155 | 156 | threadFlags=malloc(numOfWorkerThread*sizeof(threadFlags[0])); 157 | pthread_t th[numOfWorkerThread]; 158 | int threadID[numOfWorkerThread]; 159 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define ITERATION_PER_THREAD 10 9 | 10 | typedef struct 11 | { 12 | pthread_mutex_t mutex; // lock for this resource 13 | int processTime; // process time for this resource (in microseconds) 14 | } Resource; 15 | Resource *globalResources; // Shared resources among threads. resources[i] is resource type i 16 | 17 | pthread_mutex_t bigMutex; // lock for all global resources 18 | 19 | void processResource(Resource resource) 20 | { 21 | usleep(resource.processTime); // Use sleep to emulate processing time for a resource 22 | } 23 | 24 | typedef struct 25 | { 26 | int threadID; 27 | int totalResourceNum; 28 | int numOfResourceNeeded;//How many resources this thread needs to process 29 | int *resourceAccessOrder; 30 | // resourceAccessOrder[i] is the ith resource's type that this thread needs to process 31 | int ifUseBigLock;// 1 means grab all resources before processing 32 | } ThreadArgs; 33 | 34 | void printThreadArgs(ThreadArgs args) 35 | { 36 | printf("Thread %d args: \t\t totalResourceNum %d, numOfResourceNeeded %d, resourceAccessOrder(" 37 | ,args.threadID ,args.totalResourceNum ,args.numOfResourceNeeded); 38 | fflush(stdout); 39 | for(int j=0;jthreadID; 53 | int numOfResourceNeeded=para->numOfResourceNeeded; 54 | int *resourceAccessOrder=para->resourceAccessOrder; 55 | int ifUseBigLock=para->ifUseBigLock; 56 | for(int i=0;i=0;j--) 83 | { 84 | int resourceType=resourceAccessOrder[j]; 85 | pthread_mutex_unlock(&(globalResources[resourceType].mutex)); 86 | } 87 | } 88 | } 89 | } 90 | 91 | void pickKDifferentIntLessThanN(int k, int n, int *result) 92 | { 93 | //Fisher-Yates shuffling algorithm to get a random permutation of int 0...n-1 94 | int *r = malloc(n*sizeof(int)); 95 | // initial range of numbers 96 | for(int i=0;i= 0; --i) 100 | { 101 | //generate a random number [0, n-1] 102 | int j = rand() % (i+1); 103 | 104 | //swap the last element with element at random index 105 | int temp = r[i]; 106 | r[i] = r[j]; 107 | r[j] = temp; 108 | } 109 | 110 | for(int i=0;iresourceAccessOrder=malloc((thPara->numOfResourceNeeded)*sizeof(int)); 124 | pickKDifferentIntLessThanN(thPara->numOfResourceNeeded, thPara->totalResourceNum, thPara->resourceAccessOrder); 125 | if(ifSortAccess==1)//ifSortAccess: 1 all use the same ascending order 126 | qsort(thPara->resourceAccessOrder, thPara->numOfResourceNeeded, sizeof(int), compare); 127 | } 128 | 129 | int main(int argc, char *argv[]) 130 | { 131 | if(argc<3) 132 | { 133 | fprintf(stderr, "Usage: exe numOfWorkerThread totalResourceNum\n"); 134 | exit(1); 135 | } 136 | int numOfWorkerThread=atoi(argv[1]); 137 | int totalResourceNum=atoi(argv[2]); 138 | int resourceNeededPerThread=1; 139 | if(argc>3) 140 | resourceNeededPerThread=atoi(argv[3]); 141 | int ifUseBigLock=0; 142 | if(argc>4) 143 | ifUseBigLock=atoi(argv[4]); 144 | int ifSortAccess=0; 145 | if(argc>5) 146 | ifSortAccess=atoi(argv[5]); 147 | 148 | srand(time(NULL)); 149 | 150 | if(ifUseBigLock) 151 | pthread_mutex_init(&bigMutex,NULL); 152 | globalResources=malloc(sizeof(Resource)*totalResourceNum); 153 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define INPUT_JOB_NUM 10 12 | #define INPUT_FOLDER_NAME "testInput" 13 | 14 | #define THE_HEAVY_JOB_ID 1 15 | int THE_HEAVY_WEIGHT=1; 16 | 17 | #define CHUNK_SIZE 4096 18 | #define TOTAL_CHUNK_NUM 10240 19 | 20 | typedef unsigned char BYTE; 21 | 22 | char inJob[INPUT_JOB_NUM][256]; 23 | int nextJobToBeDone=0; 24 | pthread_mutex_t jobQueueMutex=PTHREAD_MUTEX_INITIALIZER; 25 | 26 | double time_diff(struct timeval x , struct timeval y) 27 | { 28 | double x_ms , y_ms , diff; 29 | x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; 30 | y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; 31 | diff = (double)y_ms - (double)x_ms; 32 | if(diff<0) 33 | { 34 | fprintf(stderr, "ERROR! time_diff<0\n"); 35 | exit(1); 36 | } 37 | return diff; 38 | } 39 | 40 | long int generateJobs() 41 | { 42 | char command[1000]; 43 | sprintf(command,"rm -rf %s",INPUT_FOLDER_NAME); 44 | int status=system(command); 45 | mkdir(INPUT_FOLDER_NAME, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 46 | BYTE writeBuf[CHUNK_SIZE]; 47 | int writeSize=0; 48 | for(int i=0;i=INPUT_JOB_NUM) 94 | { 95 | pthread_mutex_unlock(&jobQueueMutex); 96 | return -1; 97 | } 98 | currentJobID=nextJobToBeDone; 99 | nextJobToBeDone++; 100 | pthread_mutex_unlock(&jobQueueMutex); 101 | return currentJobID; 102 | } 103 | 104 | void processAJob(int jobID, long int *sum) 105 | { 106 | BYTE readBuf[CHUNK_SIZE]={0}; 107 | int readSize=0; 108 | FILE *fp; 109 | if((fp = fopen(inJob[jobID],"r"))==NULL) 110 | { 111 | perror("fopen ERROR!"); 112 | exit(1); 113 | } 114 | while(1)//Read until EOF 115 | { 116 | readSize=fread(readBuf, 1, CHUNK_SIZE, fp); 117 | if(readSize<0){ 118 | perror("read ERROR!"); 119 | exit(1); 120 | } 121 | else if(readSize==0){ //EOF 122 | break; 123 | } 124 | for(int j=0;j0) 154 | printf(","); 155 | printf("%d",whichJobIHaveDone[i]); 156 | } 157 | printf("]): \t %ld\n", sum); 158 | para->result=sum; 159 | } 160 | 161 | int main(int argc, char *argv[]) 162 | { 163 | int numOfWorkerThread=1; 164 | if(argc>=2) 165 | numOfWorkerThread=atoi(argv[1]); 166 | if(numOfWorkerThread>INPUT_JOB_NUM) 167 | numOfWorkerThread=INPUT_JOB_NUM; 168 | if(argc>=3) 169 | THE_HEAVY_WEIGHT=atoi(argv[2]); 170 | 171 | struct timeval tvGenStart,tvEnd; 172 | struct timeval tvMainStartCacl,tvMainEndCacl; 173 | struct timeval tvWorkerStartCacl,tvWorkerEndCacl; 174 | 175 | printf("Generating input jobs ...\n"); 176 | gettimeofday(&tvGenStart,NULL); 177 | long int totalBytes=generateJobs(); 178 | gettimeofday(&tvEnd,NULL); 179 | printf("Generating input jobs done. Spend %.5lf s to finish. Total test input data size is %lf MBs\n",time_diff(tvGenStart,tvEnd)/1E6,(double)totalBytes/1E6); 180 | 181 | printf("Main thread start doing jobs ...\n"); 182 | gettimeofday(&tvMainStartCacl,NULL); 183 | ThreadParas thParaMain; 184 | calcSum(&thParaMain); 185 | gettimeofday(&tvMainEndCacl,NULL); 186 | printf("Main thread finish jobs. Spend %.5lf s to finish.\n",time_diff(tvMainStartCacl,tvMainEndCacl)/1E6); 187 | 188 | nextJobToBeDone=0; 189 | printf("Worker threads start doing jobs ...\n"); 190 | gettimeofday(&tvWorkerStartCacl,NULL); 191 | pthread_t th[numOfWorkerThread]; 192 | ThreadParas thPara[numOfWorkerThread]; 193 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define INPUT_JOB_NUM 102400 13 | #define CHUNK_SIZE 4096 14 | 15 | typedef unsigned char BYTE; 16 | 17 | BYTE **inJob; 18 | int nextJobToBeDone=0; 19 | pthread_mutex_t jobQueueMutex=PTHREAD_MUTEX_INITIALIZER; 20 | 21 | sem_t fullSlots; 22 | 23 | long int *subJob; 24 | int subJobNum=0; 25 | int nextSubJobToBeDone=0; 26 | pthread_mutex_t subJobQueueMutex=PTHREAD_MUTEX_INITIALIZER; 27 | 28 | double time_diff(struct timeval x , struct timeval y) 29 | { 30 | double x_ms , y_ms , diff; 31 | x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; 32 | y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; 33 | diff = (double)y_ms - (double)x_ms; 34 | if(diff<0) 35 | { 36 | fprintf(stderr, "ERROR! time_diff<0\n"); 37 | exit(1); 38 | } 39 | return diff; 40 | } 41 | 42 | long int generateJobs() 43 | { 44 | long int totalBytes=0; 45 | inJob=malloc(INPUT_JOB_NUM*sizeof(BYTE *)); 46 | for(int i=0;i=INPUT_JOB_NUM) 64 | { 65 | pthread_mutex_unlock(&jobQueueMutex); 66 | return -1; 67 | } 68 | currentJobID=nextJobToBeDone; 69 | nextJobToBeDone++; 70 | pthread_mutex_unlock(&jobQueueMutex); 71 | return currentJobID; 72 | } 73 | 74 | void inputASubJob(long int sum) 75 | { 76 | pthread_mutex_lock(&subJobQueueMutex); 77 | if(subJobNum>=INPUT_JOB_NUM) 78 | { 79 | pthread_mutex_unlock(&subJobQueueMutex); 80 | fprintf(stderr, "subJobNum %d ERROR, exceeding INPUT_JOB_NUM %d\n", subJobNum, INPUT_JOB_NUM); 81 | exit(1); 82 | } 83 | subJob[subJobNum]=sum; 84 | subJobNum++; 85 | pthread_mutex_unlock(&subJobQueueMutex); 86 | sem_post(&fullSlots); 87 | } 88 | 89 | void processAJob(int jobID, long int *sum) 90 | { 91 | for(int j=0;jresult=sum; 119 | } 120 | 121 | void initSubJobQueue() 122 | { 123 | subJob=malloc(INPUT_JOB_NUM*sizeof(long int)); 124 | } 125 | 126 | int recvASubJob() 127 | { 128 | int currentJobID=0; 129 | sem_wait(&fullSlots); 130 | pthread_mutex_lock(&subJobQueueMutex); 131 | currentJobID=nextSubJobToBeDone; 132 | nextSubJobToBeDone++; 133 | pthread_mutex_unlock(&subJobQueueMutex); 134 | return currentJobID; 135 | } 136 | 137 | void processASubJob(int jobID) 138 | { 139 | fprintf(stderr,"%ld\n",subJob[jobID]); 140 | } 141 | 142 | void* fprintSum(void* args) { 143 | int subJobID=0; 144 | long int numOfJobsIHaveDone=0;//Remember how many jobs I have done 145 | while(1) 146 | { 147 | subJobID=recvASubJob(); 148 | processASubJob(subJobID); 149 | numOfJobsIHaveDone++; 150 | if(subJobID==INPUT_JOB_NUM-1)//All job done 151 | break; 152 | } 153 | pthread_t tid = pthread_self(); 154 | printf("[%ld] thread (fprint %ld subJobs[])\n" 155 | , pthread_self(), numOfJobsIHaveDone); 156 | } 157 | 158 | int main(int argc, char *argv[]) 159 | { 160 | int numOfWorkerThread=1; 161 | if(argc>=2) 162 | numOfWorkerThread=atoi(argv[1]); 163 | if(numOfWorkerThread>INPUT_JOB_NUM) 164 | numOfWorkerThread=INPUT_JOB_NUM; 165 | 166 | struct timeval tvGenStart,tvEnd; 167 | struct timeval tvWorkerStartCacl,tvWorkerEndCacl; 168 | 169 | printf("Generating input jobs ...\n"); 170 | gettimeofday(&tvGenStart,NULL); 171 | long int totalBytes=generateJobs(); 172 | gettimeofday(&tvEnd,NULL); 173 | printf("Generating input jobs done. Spend %.5lf s to finish. Total test input data size is %lf MBs\n",time_diff(tvGenStart,tvEnd)/1E6,(double)totalBytes/1E6); 174 | 175 | sem_init(&fullSlots, 0, 0); 176 | initSubJobQueue(); 177 | nextJobToBeDone=0; 178 | nextSubJobToBeDone=0; 179 | printf("Worker threads start doing jobs ...\n"); 180 | gettimeofday(&tvWorkerStartCacl,NULL); 181 | pthread_t th[numOfWorkerThread]; 182 | ThreadParas thPara[numOfWorkerThread]; 183 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define INPUT_JOB_NUM 102400 12 | #define CHUNK_SIZE 4096 13 | 14 | typedef unsigned char BYTE; 15 | 16 | BYTE **inJob; 17 | int nextJobToBeDone=0; 18 | pthread_mutex_t jobQueueMutex=PTHREAD_MUTEX_INITIALIZER; 19 | 20 | double time_diff(struct timeval x , struct timeval y) 21 | { 22 | double x_ms , y_ms , diff; 23 | x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; 24 | y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; 25 | diff = (double)y_ms - (double)x_ms; 26 | if(diff<0) 27 | { 28 | fprintf(stderr, "ERROR! time_diff<0\n"); 29 | exit(1); 30 | } 31 | return diff; 32 | } 33 | 34 | long int generateJobs() 35 | { 36 | long int totalBytes=0; 37 | inJob=malloc(INPUT_JOB_NUM*sizeof(BYTE *)); 38 | for(int i=0;i=INPUT_JOB_NUM) 56 | { 57 | pthread_mutex_unlock(&jobQueueMutex); 58 | return -1; 59 | } 60 | currentJobID=nextJobToBeDone; 61 | nextJobToBeDone++; 62 | pthread_mutex_unlock(&jobQueueMutex); 63 | return currentJobID; 64 | } 65 | 66 | void processAJob(int jobID, long int *sum) 67 | { 68 | for(int j=0;jresult=sum; 96 | } 97 | 98 | int main(int argc, char *argv[]) 99 | { 100 | int numOfWorkerThread=1; 101 | if(argc>=2) 102 | numOfWorkerThread=atoi(argv[1]); 103 | if(numOfWorkerThread>INPUT_JOB_NUM) 104 | numOfWorkerThread=INPUT_JOB_NUM; 105 | 106 | struct timeval tvGenStart,tvEnd; 107 | struct timeval tvWorkerStartCacl,tvWorkerEndCacl; 108 | 109 | printf("Generating input jobs ...\n"); 110 | gettimeofday(&tvGenStart,NULL); 111 | long int totalBytes=generateJobs(); 112 | gettimeofday(&tvEnd,NULL); 113 | printf("Generating input jobs done. Spend %.5lf s to finish. Total test input data size is %lf MBs\n",time_diff(tvGenStart,tvEnd)/1E6,(double)totalBytes/1E6); 114 | 115 | nextJobToBeDone=0; 116 | printf("Worker threads start doing jobs ...\n"); 117 | gettimeofday(&tvWorkerStartCacl,NULL); 118 | pthread_t th[numOfWorkerThread]; 119 | ThreadParas thPara[numOfWorkerThread]; 120 | for(int i=0;i. 15 | 16 | CC = gcc 17 | CPPFLAGS = -O2 -pthread 18 | 19 | # the build target executable: 20 | TARGETS = ATMProblemShow ATMProblemShow-mutex \ 21 | BoundedBuffer-mutex BoundedBuffer-semaphore BoundedBuffer-monitor BoundedBuffer-monitor-mesatest \ 22 | Deadlock PreAssignJob DynamicAssignJob HomoThreads HeteroThreads \ 23 | ConcurrentWget-ThreadPool ConcurrentWget-OnDemand \ 24 | ConcurrentQuickSort-Recursive-broken ConcurrentQuickSort-Recursive ConcurrentQuickSort-Iteration \ 25 | Problems-CompilerOptimization Problems-CPUOoO 26 | 27 | all: $(TARGETS) 28 | 29 | clean: 30 | $(RM) $(TARGETS) 31 | 32 | -------------------------------------------------------------------------------- /CodeInSlides/chapter4/MultiCat.sh: -------------------------------------------------------------------------------- 1 | if [ "x$1$2" == "x$1" ] 2 | then 3 | echo "Input arg1[filename], arg2[times]" 4 | exit 5 | fi 6 | 7 | for ((i=0;i<$2;i++)) 8 | do 9 | cat $1 10 | done -------------------------------------------------------------------------------- /CodeInSlides/chapter4/PreAssignJob.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define INPUT_JOB_NUM 10 12 | #define INPUT_FOLDER_NAME "testInput" 13 | 14 | #define THE_HEAVY_JOB_ID 1 15 | int THE_HEAVY_WEIGHT=1; 16 | 17 | #define CHUNK_SIZE 4096 18 | #define TOTAL_CHUNK_NUM 10240 19 | 20 | typedef unsigned char BYTE; 21 | 22 | char inJob[INPUT_JOB_NUM][256]; 23 | 24 | double time_diff(struct timeval x , struct timeval y) 25 | { 26 | double x_ms , y_ms , diff; 27 | x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; 28 | y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; 29 | diff = (double)y_ms - (double)x_ms; 30 | if(diff<0) 31 | { 32 | fprintf(stderr, "ERROR! time_diff<0\n"); 33 | exit(1); 34 | } 35 | return diff; 36 | } 37 | 38 | long int generateJobs() 39 | { 40 | char command[1000]; 41 | sprintf(command,"rm -rf %s",INPUT_FOLDER_NAME); 42 | int status=system(command); 43 | mkdir(INPUT_FOLDER_NAME, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 44 | BYTE writeBuf[CHUNK_SIZE]; 45 | int writeSize=0; 46 | for(int i=0;ifirst; 119 | int last=para->last; 120 | long int sum=0; 121 | for(int i=first;iresult=sum; 132 | } 133 | 134 | int main(int argc, char *argv[]) 135 | { 136 | int numOfWorkerThread=1; 137 | if(argc>=2) 138 | numOfWorkerThread=atoi(argv[1]); 139 | if(numOfWorkerThread>INPUT_JOB_NUM) 140 | numOfWorkerThread=INPUT_JOB_NUM; 141 | if(argc>=3) 142 | THE_HEAVY_WEIGHT=atoi(argv[2]); 143 | 144 | struct timeval tvGenStart,tvEnd; 145 | struct timeval tvMainStartCacl,tvMainEndCacl; 146 | struct timeval tvWorkerStartCacl,tvWorkerEndCacl; 147 | 148 | printf("Generating input jobs ...\n"); 149 | gettimeofday(&tvGenStart,NULL); 150 | long int totalBytes=generateJobs(); 151 | gettimeofday(&tvEnd,NULL); 152 | printf("Generating input jobs done. Spend %.5lf s to finish. Total test input data size is %lf MBs\n",time_diff(tvGenStart,tvEnd)/1E6,(double)totalBytes/1E6); 153 | 154 | printf("Main thread start doing jobs ...\n"); 155 | gettimeofday(&tvMainStartCacl,NULL); 156 | ThreadParas thParaMain; 157 | thParaMain.first=0; 158 | thParaMain.last=INPUT_JOB_NUM; 159 | calcSum(&thParaMain); 160 | gettimeofday(&tvMainEndCacl,NULL); 161 | printf("Main thread finish jobs. Spend %.5lf s to finish.\n",time_diff(tvMainStartCacl,tvMainEndCacl)/1E6); 162 | 163 | printf("Worker threads start doing jobs ...\n"); 164 | gettimeofday(&tvWorkerStartCacl,NULL); 165 | pthread_t th[numOfWorkerThread]; 166 | ThreadParas thPara[numOfWorkerThread]; 167 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | long TEST_TIMES=1000000; 9 | #define PRINT_STEP 10000 10 | 11 | int x=0,y=0; 12 | void* thread_1(void* args) { 13 | x = 1; printf("y=%d\n", y); 14 | } 15 | 16 | void* thread_2(void* args) { 17 | y = 1; printf("x=%d\n", x); 18 | } 19 | 20 | int main(int argc, char *argv[]) 21 | { 22 | if(argc>=2) 23 | TEST_TIMES=atoi(argv[1]); 24 | 25 | pthread_t th1; 26 | pthread_t th2; 27 | for(int i=0;i: 8 | 630: 48 83 ec 08 sub $0x8,%rsp 9 | 634: 48 8b 05 ad 09 20 00 mov 0x2009ad(%rip),%rax # 200fe8 <__gmon_start__> 10 | 63b: 48 85 c0 test %rax,%rax 11 | 63e: 74 02 je 642 <_init+0x12> 12 | 640: ff d0 callq *%rax 13 | 642: 48 83 c4 08 add $0x8,%rsp 14 | 646: c3 retq 15 | 16 | Disassembly of section .plt: 17 | 18 | 0000000000000650 <.plt>: 19 | 650: ff 35 4a 09 20 00 pushq 0x20094a(%rip) # 200fa0 <_GLOBAL_OFFSET_TABLE_+0x8> 20 | 656: ff 25 4c 09 20 00 jmpq *0x20094c(%rip) # 200fa8 <_GLOBAL_OFFSET_TABLE_+0x10> 21 | 65c: 0f 1f 40 00 nopl 0x0(%rax) 22 | 23 | 0000000000000660 : 24 | 660: ff 25 4a 09 20 00 jmpq *0x20094a(%rip) # 200fb0 25 | 666: 68 00 00 00 00 pushq $0x0 26 | 66b: e9 e0 ff ff ff jmpq 650 <.plt> 27 | 28 | 0000000000000670 <__printf_chk@plt>: 29 | 670: ff 25 42 09 20 00 jmpq *0x200942(%rip) # 200fb8 <__printf_chk@GLIBC_2.3.4> 30 | 676: 68 01 00 00 00 pushq $0x1 31 | 67b: e9 d0 ff ff ff jmpq 650 <.plt> 32 | 33 | 0000000000000680 : 34 | 680: ff 25 3a 09 20 00 jmpq *0x20093a(%rip) # 200fc0 35 | 686: 68 02 00 00 00 pushq $0x2 36 | 68b: e9 c0 ff ff ff jmpq 650 <.plt> 37 | 38 | 0000000000000690 : 39 | 690: ff 25 32 09 20 00 jmpq *0x200932(%rip) # 200fc8 40 | 696: 68 03 00 00 00 pushq $0x3 41 | 69b: e9 b0 ff ff ff jmpq 650 <.plt> 42 | 43 | 00000000000006a0 : 44 | 6a0: ff 25 2a 09 20 00 jmpq *0x20092a(%rip) # 200fd0 45 | 6a6: 68 04 00 00 00 pushq $0x4 46 | 6ab: e9 a0 ff ff ff jmpq 650 <.plt> 47 | 48 | Disassembly of section .plt.got: 49 | 50 | 00000000000006b0 <__cxa_finalize@plt>: 51 | 6b0: ff 25 42 09 20 00 jmpq *0x200942(%rip) # 200ff8 <__cxa_finalize@GLIBC_2.2.5> 52 | 6b6: 66 90 xchg %ax,%ax 53 | 54 | Disassembly of section .text: 55 | 56 | 00000000000006c0
: 57 | 6c0: 53 push %rbx 58 | 6c1: 48 8d 15 a8 01 00 00 lea 0x1a8(%rip),%rdx # 870 59 | 6c8: 31 c9 xor %ecx,%ecx 60 | 6ca: 31 f6 xor %esi,%esi 61 | 6cc: 48 83 ec 20 sub $0x20,%rsp 62 | 6d0: 48 89 e3 mov %rsp,%rbx 63 | 6d3: 48 89 df mov %rbx,%rdi 64 | 6d6: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax 65 | 6dd: 00 00 66 | 6df: 48 89 44 24 18 mov %rax,0x18(%rsp) 67 | 6e4: 31 c0 xor %eax,%eax 68 | 6e6: e8 75 ff ff ff callq 660 69 | 6eb: 85 c0 test %eax,%eax 70 | 6ed: 75 50 jne 73f 71 | 6ef: 48 8d 7b 08 lea 0x8(%rbx),%rdi 72 | 6f3: 48 8d 15 76 01 00 00 lea 0x176(%rip),%rdx # 870 73 | 6fa: 31 c9 xor %ecx,%ecx 74 | 6fc: 31 f6 xor %esi,%esi 75 | 6fe: e8 5d ff ff ff callq 660 76 | 703: 85 c0 test %eax,%eax 77 | 705: 75 38 jne 73f 78 | 707: 48 8b 3c 24 mov (%rsp),%rdi 79 | 70b: 31 f6 xor %esi,%esi 80 | 70d: e8 7e ff ff ff callq 690 81 | 712: 48 8b 7c 24 08 mov 0x8(%rsp),%rdi 82 | 717: 31 f6 xor %esi,%esi 83 | 719: e8 72 ff ff ff callq 690 84 | 71e: 48 8b 15 f3 08 20 00 mov 0x2008f3(%rip),%rdx # 201018 85 | 725: 48 8d 35 d8 01 00 00 lea 0x1d8(%rip),%rsi # 904 <_IO_stdin_used+0x4> 86 | 72c: bf 01 00 00 00 mov $0x1,%edi 87 | 731: 31 c0 xor %eax,%eax 88 | 733: e8 38 ff ff ff callq 670 <__printf_chk@plt> 89 | 738: 31 ff xor %edi,%edi 90 | 73a: e8 61 ff ff ff callq 6a0 91 | 73f: 48 8d 3d c9 01 00 00 lea 0x1c9(%rip),%rdi # 90f <_IO_stdin_used+0xf> 92 | 746: e8 35 ff ff ff callq 680 93 | 74b: bf 01 00 00 00 mov $0x1,%edi 94 | 750: e8 4b ff ff ff callq 6a0 95 | 755: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 96 | 75c: 00 00 00 97 | 75f: 90 nop 98 | 99 | 0000000000000760 <_start>: 100 | 760: 31 ed xor %ebp,%ebp 101 | 762: 49 89 d1 mov %rdx,%r9 102 | 765: 5e pop %rsi 103 | 766: 48 89 e2 mov %rsp,%rdx 104 | 769: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 105 | 76d: 50 push %rax 106 | 76e: 54 push %rsp 107 | 76f: 4c 8d 05 7a 01 00 00 lea 0x17a(%rip),%r8 # 8f0 <__libc_csu_fini> 108 | 776: 48 8d 0d 03 01 00 00 lea 0x103(%rip),%rcx # 880 <__libc_csu_init> 109 | 77d: 48 8d 3d 3c ff ff ff lea -0xc4(%rip),%rdi # 6c0
110 | 784: ff 15 56 08 20 00 callq *0x200856(%rip) # 200fe0 <__libc_start_main@GLIBC_2.2.5> 111 | 78a: f4 hlt 112 | 78b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) 113 | 114 | 0000000000000790 : 115 | 790: 48 8d 3d 79 08 20 00 lea 0x200879(%rip),%rdi # 201010 <__TMC_END__> 116 | 797: 55 push %rbp 117 | 798: 48 8d 05 71 08 20 00 lea 0x200871(%rip),%rax # 201010 <__TMC_END__> 118 | 79f: 48 39 f8 cmp %rdi,%rax 119 | 7a2: 48 89 e5 mov %rsp,%rbp 120 | 7a5: 74 19 je 7c0 121 | 7a7: 48 8b 05 2a 08 20 00 mov 0x20082a(%rip),%rax # 200fd8 <_ITM_deregisterTMCloneTable> 122 | 7ae: 48 85 c0 test %rax,%rax 123 | 7b1: 74 0d je 7c0 124 | 7b3: 5d pop %rbp 125 | 7b4: ff e0 jmpq *%rax 126 | 7b6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 127 | 7bd: 00 00 00 128 | 7c0: 5d pop %rbp 129 | 7c1: c3 retq 130 | 7c2: 0f 1f 40 00 nopl 0x0(%rax) 131 | 7c6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 132 | 7cd: 00 00 00 133 | 134 | 00000000000007d0 : 135 | 7d0: 48 8d 3d 39 08 20 00 lea 0x200839(%rip),%rdi # 201010 <__TMC_END__> 136 | 7d7: 48 8d 35 32 08 20 00 lea 0x200832(%rip),%rsi # 201010 <__TMC_END__> 137 | 7de: 55 push %rbp 138 | 7df: 48 29 fe sub %rdi,%rsi 139 | 7e2: 48 89 e5 mov %rsp,%rbp 140 | 7e5: 48 c1 fe 03 sar $0x3,%rsi 141 | 7e9: 48 89 f0 mov %rsi,%rax 142 | 7ec: 48 c1 e8 3f shr $0x3f,%rax 143 | 7f0: 48 01 c6 add %rax,%rsi 144 | 7f3: 48 d1 fe sar %rsi 145 | 7f6: 74 18 je 810 146 | 7f8: 48 8b 05 f1 07 20 00 mov 0x2007f1(%rip),%rax # 200ff0 <_ITM_registerTMCloneTable> 147 | 7ff: 48 85 c0 test %rax,%rax 148 | 802: 74 0c je 810 149 | 804: 5d pop %rbp 150 | 805: ff e0 jmpq *%rax 151 | 807: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) 152 | 80e: 00 00 153 | 810: 5d pop %rbp 154 | 811: c3 retq 155 | 812: 0f 1f 40 00 nopl 0x0(%rax) 156 | 816: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 157 | 81d: 00 00 00 158 | 159 | 0000000000000820 <__do_global_dtors_aux>: 160 | 820: 80 3d e9 07 20 00 00 cmpb $0x0,0x2007e9(%rip) # 201010 <__TMC_END__> 161 | 827: 75 2f jne 858 <__do_global_dtors_aux+0x38> 162 | 829: 48 83 3d c7 07 20 00 cmpq $0x0,0x2007c7(%rip) # 200ff8 <__cxa_finalize@GLIBC_2.2.5> 163 | 830: 00 164 | 831: 55 push %rbp 165 | 832: 48 89 e5 mov %rsp,%rbp 166 | 835: 74 0c je 843 <__do_global_dtors_aux+0x23> 167 | 837: 48 8b 3d ca 07 20 00 mov 0x2007ca(%rip),%rdi # 201008 <__dso_handle> 168 | 83e: e8 6d fe ff ff callq 6b0 <__cxa_finalize@plt> 169 | 843: e8 48 ff ff ff callq 790 170 | 848: c6 05 c1 07 20 00 01 movb $0x1,0x2007c1(%rip) # 201010 <__TMC_END__> 171 | 84f: 5d pop %rbp 172 | 850: c3 retq 173 | 851: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 174 | 858: f3 c3 repz retq 175 | 85a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 176 | 177 | 0000000000000860 : 178 | 860: 55 push %rbp 179 | 861: 48 89 e5 mov %rsp,%rbp 180 | 864: 5d pop %rbp 181 | 865: e9 66 ff ff ff jmpq 7d0 182 | 86a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 183 | 184 | 0000000000000870 : 185 | 870: 48 81 05 9d 07 20 00 addq $0x5f5e100,0x20079d(%rip) # 201018 186 | 877: 00 e1 f5 05 187 | 87b: c3 retq 188 | 87c: 0f 1f 40 00 nopl 0x0(%rax) 189 | 190 | 0000000000000880 <__libc_csu_init>: 191 | 880: 41 57 push %r15 192 | 882: 41 56 push %r14 193 | 884: 49 89 d7 mov %rdx,%r15 194 | 887: 41 55 push %r13 195 | 889: 41 54 push %r12 196 | 88b: 4c 8d 25 f6 04 20 00 lea 0x2004f6(%rip),%r12 # 200d88 <__frame_dummy_init_array_entry> 197 | 892: 55 push %rbp 198 | 893: 48 8d 2d f6 04 20 00 lea 0x2004f6(%rip),%rbp # 200d90 <__init_array_end> 199 | 89a: 53 push %rbx 200 | 89b: 41 89 fd mov %edi,%r13d 201 | 89e: 49 89 f6 mov %rsi,%r14 202 | 8a1: 4c 29 e5 sub %r12,%rbp 203 | 8a4: 48 83 ec 08 sub $0x8,%rsp 204 | 8a8: 48 c1 fd 03 sar $0x3,%rbp 205 | 8ac: e8 7f fd ff ff callq 630 <_init> 206 | 8b1: 48 85 ed test %rbp,%rbp 207 | 8b4: 74 20 je 8d6 <__libc_csu_init+0x56> 208 | 8b6: 31 db xor %ebx,%ebx 209 | 8b8: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1) 210 | 8bf: 00 211 | 8c0: 4c 89 fa mov %r15,%rdx 212 | 8c3: 4c 89 f6 mov %r14,%rsi 213 | 8c6: 44 89 ef mov %r13d,%edi 214 | 8c9: 41 ff 14 dc callq *(%r12,%rbx,8) 215 | 8cd: 48 83 c3 01 add $0x1,%rbx 216 | 8d1: 48 39 dd cmp %rbx,%rbp 217 | 8d4: 75 ea jne 8c0 <__libc_csu_init+0x40> 218 | 8d6: 48 83 c4 08 add $0x8,%rsp 219 | 8da: 5b pop %rbx 220 | 8db: 5d pop %rbp 221 | 8dc: 41 5c pop %r12 222 | 8de: 41 5d pop %r13 223 | 8e0: 41 5e pop %r14 224 | 8e2: 41 5f pop %r15 225 | 8e4: c3 retq 226 | 8e5: 90 nop 227 | 8e6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 228 | 8ed: 00 00 00 229 | 230 | 00000000000008f0 <__libc_csu_fini>: 231 | 8f0: f3 c3 repz retq 232 | 233 | Disassembly of section .fini: 234 | 235 | 00000000000008f4 <_fini>: 236 | 8f4: 48 83 ec 08 sub $0x8,%rsp 237 | 8f8: 48 83 c4 08 add $0x8,%rsp 238 | 8fc: c3 retq 239 | -------------------------------------------------------------------------------- /CodeInSlides/chapter4/Problems-CompilerOptimization.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define n 100000000 9 | long sum = 0; 10 | 11 | void* do_sum(void* args) { 12 | for (int i = 0; i < n; i++) sum++; 13 | } 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | pthread_t th[2]; 18 | for(int i=0;i<2;i++) 19 | { 20 | if(pthread_create(&th[i], NULL, do_sum, NULL)!=0) 21 | { 22 | perror("pthread_create failed"); 23 | exit(1); 24 | } 25 | } 26 | for(int i=0;i<2;i++) 27 | pthread_join(th[i], NULL); 28 | 29 | printf("sum = %ld\n", sum); 30 | exit(0); 31 | } -------------------------------------------------------------------------------- /CodeInSlides/chapter4/Statistics_for_x&y.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | 4 | default_input_path = './test.log' 5 | 6 | 7 | 8 | def parse_args(): 9 | parser = argparse.ArgumentParser(description='Statistics for x&y of one file') 10 | parser.add_argument( '-i', '--input', type=str, default=default_input_path, 11 | help='The input file for testing. Default: ./test.log') 12 | 13 | args = parser.parse_args() 14 | return args 15 | 16 | 17 | def main(): 18 | args = parse_args() 19 | with open(args.input, 'r', encoding='utf-8') as file: 20 | lines = file.read() 21 | 22 | lines = lines.replace('\r','').replace('\n\n', '\n').split('\n')[:-1] 23 | # print(lines) 24 | lines_number = len(lines) 25 | print('totally read %d lines.' % lines_number) 26 | 27 | judge_table = {} 28 | judge_table['x=0'] = 0 29 | judge_table['x=1'] = 2 30 | judge_table['y=0'] = 0 31 | judge_table['y=1'] = 1 32 | x_flag = False 33 | y_flag = False 34 | result_table = ['x=0, y=0', 'x=0, y=1', 'x=1, y=0', 'x=1, y=1', 'invalid'] 35 | result_count = [0, 0, 0, 0, 0] 36 | correct_count = 0 37 | 38 | 39 | current_line_index = 0 40 | while current_line_index < lines_number: 41 | x_flag = False 42 | y_flag = False 43 | result_type = 0 44 | for index_tail in range(2): 45 | line_invalid_flag = False 46 | tmp_line_index = current_line_index + index_tail 47 | tmp_line = lines[tmp_line_index] 48 | # print(tmp_line) 49 | if tmp_line == 'x=0' or tmp_line == 'x=1': 50 | x_flag = True 51 | elif tmp_line == 'y=0' or tmp_line == 'y=1': 52 | y_flag = True 53 | else: 54 | line_invalid_flag = True 55 | if not line_invalid_flag: 56 | result_type = result_type + judge_table[tmp_line] 57 | 58 | if not(x_flag and y_flag): 59 | result_type = 4 60 | else: 61 | correct_count += 1 62 | result_count[result_type] += 1 63 | 64 | current_line_index = current_line_index + 2 65 | 66 | for type_index in range(4): 67 | print('Type: {}:\n In total {} case(s). {}%'.format(result_table[type_index], result_count[type_index], result_count[type_index]*100 / correct_count ) ) 68 | print('Type: {}:\n In total {} case(s).'.format(result_table[4], result_count[4]) ) 69 | pass 70 | 71 | 72 | 73 | if __name__ == '__main__': 74 | main() 75 | pass -------------------------------------------------------------------------------- /CodeInSlides/chapter4/testUrl.in: -------------------------------------------------------------------------------- 1 | https://www.baidu.com/ 2 | https://www.sina.com.cn/ 3 | https://www.163.com/ 4 | https://www.sohu.com/ 5 | https://www.taobao.com/ 6 | https://www.jd.com/ 7 | -------------------------------------------------------------------------------- /CodeInSlides/chapter5/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010 Benoit Sigoure 2 | # 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program. If not, see . 15 | 16 | CC = gcc 17 | CFLAGS = -O2 -pthread 18 | 19 | # the build target executable: 20 | TARGETS = Measure-ALU Measure-ALU-broken Measure-ALU-broken-simplified Measure-mutex-syscall Measure-mutex-CTXswitch\ 21 | PrintToMonitor 22 | 23 | all: $(TARGETS) 24 | 25 | clean: 26 | $(RM) $(TARGETS) 27 | 28 | -------------------------------------------------------------------------------- /CodeInSlides/chapter5/Measure-ALU-broken-simplified-O1.s: -------------------------------------------------------------------------------- 1 | 2 | Measure-ALU-broken-simplified: file format elf64-x86-64 3 | 4 | 5 | Disassembly of section .init: 6 | 7 | 00000000000004b8 <_init>: 8 | 4b8: 48 83 ec 08 sub $0x8,%rsp 9 | 4bc: 48 8b 05 25 0b 20 00 mov 0x200b25(%rip),%rax # 200fe8 <__gmon_start__> 10 | 4c3: 48 85 c0 test %rax,%rax 11 | 4c6: 74 02 je 4ca <_init+0x12> 12 | 4c8: ff d0 callq *%rax 13 | 4ca: 48 83 c4 08 add $0x8,%rsp 14 | 4ce: c3 retq 15 | 16 | Disassembly of section .plt: 17 | 18 | 00000000000004d0 <.plt>: 19 | 4d0: ff 35 f2 0a 20 00 pushq 0x200af2(%rip) # 200fc8 <_GLOBAL_OFFSET_TABLE_+0x8> 20 | 4d6: ff 25 f4 0a 20 00 jmpq *0x200af4(%rip) # 200fd0 <_GLOBAL_OFFSET_TABLE_+0x10> 21 | 4dc: 0f 1f 40 00 nopl 0x0(%rax) 22 | 23 | Disassembly of section .plt.got: 24 | 25 | 00000000000004e0 <__cxa_finalize@plt>: 26 | 4e0: ff 25 12 0b 20 00 jmpq *0x200b12(%rip) # 200ff8 <__cxa_finalize@GLIBC_2.2.5> 27 | 4e6: 66 90 xchg %ax,%ax 28 | 29 | Disassembly of section .text: 30 | 31 | 00000000000004f0 <_start>: 32 | 4f0: 31 ed xor %ebp,%ebp 33 | 4f2: 49 89 d1 mov %rdx,%r9 34 | 4f5: 5e pop %rsi 35 | 4f6: 48 89 e2 mov %rsp,%rdx 36 | 4f9: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 37 | 4fd: 50 push %rax 38 | 4fe: 54 push %rsp 39 | 4ff: 4c 8d 05 aa 01 00 00 lea 0x1aa(%rip),%r8 # 6b0 <__libc_csu_fini> 40 | 506: 48 8d 0d 33 01 00 00 lea 0x133(%rip),%rcx # 640 <__libc_csu_init> 41 | 50d: 48 8d 3d e6 00 00 00 lea 0xe6(%rip),%rdi # 5fa
42 | 514: ff 15 c6 0a 20 00 callq *0x200ac6(%rip) # 200fe0 <__libc_start_main@GLIBC_2.2.5> 43 | 51a: f4 hlt 44 | 51b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) 45 | 46 | 0000000000000520 : 47 | 520: 48 8d 3d e9 0a 20 00 lea 0x200ae9(%rip),%rdi # 201010 <__TMC_END__> 48 | 527: 55 push %rbp 49 | 528: 48 8d 05 e1 0a 20 00 lea 0x200ae1(%rip),%rax # 201010 <__TMC_END__> 50 | 52f: 48 39 f8 cmp %rdi,%rax 51 | 532: 48 89 e5 mov %rsp,%rbp 52 | 535: 74 19 je 550 53 | 537: 48 8b 05 9a 0a 20 00 mov 0x200a9a(%rip),%rax # 200fd8 <_ITM_deregisterTMCloneTable> 54 | 53e: 48 85 c0 test %rax,%rax 55 | 541: 74 0d je 550 56 | 543: 5d pop %rbp 57 | 544: ff e0 jmpq *%rax 58 | 546: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 59 | 54d: 00 00 00 60 | 550: 5d pop %rbp 61 | 551: c3 retq 62 | 552: 0f 1f 40 00 nopl 0x0(%rax) 63 | 556: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 64 | 55d: 00 00 00 65 | 66 | 0000000000000560 : 67 | 560: 48 8d 3d a9 0a 20 00 lea 0x200aa9(%rip),%rdi # 201010 <__TMC_END__> 68 | 567: 48 8d 35 a2 0a 20 00 lea 0x200aa2(%rip),%rsi # 201010 <__TMC_END__> 69 | 56e: 55 push %rbp 70 | 56f: 48 29 fe sub %rdi,%rsi 71 | 572: 48 89 e5 mov %rsp,%rbp 72 | 575: 48 c1 fe 03 sar $0x3,%rsi 73 | 579: 48 89 f0 mov %rsi,%rax 74 | 57c: 48 c1 e8 3f shr $0x3f,%rax 75 | 580: 48 01 c6 add %rax,%rsi 76 | 583: 48 d1 fe sar %rsi 77 | 586: 74 18 je 5a0 78 | 588: 48 8b 05 61 0a 20 00 mov 0x200a61(%rip),%rax # 200ff0 <_ITM_registerTMCloneTable> 79 | 58f: 48 85 c0 test %rax,%rax 80 | 592: 74 0c je 5a0 81 | 594: 5d pop %rbp 82 | 595: ff e0 jmpq *%rax 83 | 597: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) 84 | 59e: 00 00 85 | 5a0: 5d pop %rbp 86 | 5a1: c3 retq 87 | 5a2: 0f 1f 40 00 nopl 0x0(%rax) 88 | 5a6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 89 | 5ad: 00 00 00 90 | 91 | 00000000000005b0 <__do_global_dtors_aux>: 92 | 5b0: 80 3d 59 0a 20 00 00 cmpb $0x0,0x200a59(%rip) # 201010 <__TMC_END__> 93 | 5b7: 75 2f jne 5e8 <__do_global_dtors_aux+0x38> 94 | 5b9: 48 83 3d 37 0a 20 00 cmpq $0x0,0x200a37(%rip) # 200ff8 <__cxa_finalize@GLIBC_2.2.5> 95 | 5c0: 00 96 | 5c1: 55 push %rbp 97 | 5c2: 48 89 e5 mov %rsp,%rbp 98 | 5c5: 74 0c je 5d3 <__do_global_dtors_aux+0x23> 99 | 5c7: 48 8b 3d 3a 0a 20 00 mov 0x200a3a(%rip),%rdi # 201008 <__dso_handle> 100 | 5ce: e8 0d ff ff ff callq 4e0 <__cxa_finalize@plt> 101 | 5d3: e8 48 ff ff ff callq 520 102 | 5d8: c6 05 31 0a 20 00 01 movb $0x1,0x200a31(%rip) # 201010 <__TMC_END__> 103 | 5df: 5d pop %rbp 104 | 5e0: c3 retq 105 | 5e1: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 106 | 5e8: f3 c3 repz retq 107 | 5ea: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 108 | 109 | 00000000000005f0 : 110 | 5f0: 55 push %rbp 111 | 5f1: 48 89 e5 mov %rsp,%rbp 112 | 5f4: 5d pop %rbp 113 | 5f5: e9 66 ff ff ff jmpq 560 114 | 115 | 00000000000005fa
: 116 | 5fa: b8 00 ca 9a 3b mov $0x3b9aca00,%eax 117 | 5ff: 83 e8 01 sub $0x1,%eax 118 | 602: 75 fb jne 5ff 119 | 604: b8 00 ca 9a 3b mov $0x3b9aca00,%eax 120 | 609: 83 e8 01 sub $0x1,%eax 121 | 60c: 75 fb jne 609 122 | 60e: b8 00 ca 9a 3b mov $0x3b9aca00,%eax 123 | 613: 83 e8 01 sub $0x1,%eax 124 | 616: 75 fb jne 613 125 | 618: b8 00 ca 9a 3b mov $0x3b9aca00,%eax 126 | 61d: 83 e8 01 sub $0x1,%eax 127 | 620: 75 fb jne 61d 128 | 622: b8 00 ca 9a 3b mov $0x3b9aca00,%eax 129 | 627: 83 e8 01 sub $0x1,%eax 130 | 62a: 75 fb jne 627 131 | 62c: b8 00 00 00 00 mov $0x0,%eax 132 | 631: c3 retq 133 | 632: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 134 | 639: 00 00 00 135 | 63c: 0f 1f 40 00 nopl 0x0(%rax) 136 | 137 | 0000000000000640 <__libc_csu_init>: 138 | 640: 41 57 push %r15 139 | 642: 41 56 push %r14 140 | 644: 49 89 d7 mov %rdx,%r15 141 | 647: 41 55 push %r13 142 | 649: 41 54 push %r12 143 | 64b: 4c 8d 25 9e 07 20 00 lea 0x20079e(%rip),%r12 # 200df0 <__frame_dummy_init_array_entry> 144 | 652: 55 push %rbp 145 | 653: 48 8d 2d 9e 07 20 00 lea 0x20079e(%rip),%rbp # 200df8 <__init_array_end> 146 | 65a: 53 push %rbx 147 | 65b: 41 89 fd mov %edi,%r13d 148 | 65e: 49 89 f6 mov %rsi,%r14 149 | 661: 4c 29 e5 sub %r12,%rbp 150 | 664: 48 83 ec 08 sub $0x8,%rsp 151 | 668: 48 c1 fd 03 sar $0x3,%rbp 152 | 66c: e8 47 fe ff ff callq 4b8 <_init> 153 | 671: 48 85 ed test %rbp,%rbp 154 | 674: 74 20 je 696 <__libc_csu_init+0x56> 155 | 676: 31 db xor %ebx,%ebx 156 | 678: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1) 157 | 67f: 00 158 | 680: 4c 89 fa mov %r15,%rdx 159 | 683: 4c 89 f6 mov %r14,%rsi 160 | 686: 44 89 ef mov %r13d,%edi 161 | 689: 41 ff 14 dc callq *(%r12,%rbx,8) 162 | 68d: 48 83 c3 01 add $0x1,%rbx 163 | 691: 48 39 dd cmp %rbx,%rbp 164 | 694: 75 ea jne 680 <__libc_csu_init+0x40> 165 | 696: 48 83 c4 08 add $0x8,%rsp 166 | 69a: 5b pop %rbx 167 | 69b: 5d pop %rbp 168 | 69c: 41 5c pop %r12 169 | 69e: 41 5d pop %r13 170 | 6a0: 41 5e pop %r14 171 | 6a2: 41 5f pop %r15 172 | 6a4: c3 retq 173 | 6a5: 90 nop 174 | 6a6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 175 | 6ad: 00 00 00 176 | 177 | 00000000000006b0 <__libc_csu_fini>: 178 | 6b0: f3 c3 repz retq 179 | 180 | Disassembly of section .fini: 181 | 182 | 00000000000006b4 <_fini>: 183 | 6b4: 48 83 ec 08 sub $0x8,%rsp 184 | 6b8: 48 83 c4 08 add $0x8,%rsp 185 | 6bc: c3 retq 186 | -------------------------------------------------------------------------------- /CodeInSlides/chapter5/Measure-ALU-broken-simplified-O2.s: -------------------------------------------------------------------------------- 1 | 2 | Measure-ALU-broken-simplified: file format elf64-x86-64 3 | 4 | 5 | Disassembly of section .init: 6 | 7 | 00000000000004b8 <_init>: 8 | 4b8: 48 83 ec 08 sub $0x8,%rsp 9 | 4bc: 48 8b 05 25 0b 20 00 mov 0x200b25(%rip),%rax # 200fe8 <__gmon_start__> 10 | 4c3: 48 85 c0 test %rax,%rax 11 | 4c6: 74 02 je 4ca <_init+0x12> 12 | 4c8: ff d0 callq *%rax 13 | 4ca: 48 83 c4 08 add $0x8,%rsp 14 | 4ce: c3 retq 15 | 16 | Disassembly of section .plt: 17 | 18 | 00000000000004d0 <.plt>: 19 | 4d0: ff 35 f2 0a 20 00 pushq 0x200af2(%rip) # 200fc8 <_GLOBAL_OFFSET_TABLE_+0x8> 20 | 4d6: ff 25 f4 0a 20 00 jmpq *0x200af4(%rip) # 200fd0 <_GLOBAL_OFFSET_TABLE_+0x10> 21 | 4dc: 0f 1f 40 00 nopl 0x0(%rax) 22 | 23 | Disassembly of section .plt.got: 24 | 25 | 00000000000004e0 <__cxa_finalize@plt>: 26 | 4e0: ff 25 12 0b 20 00 jmpq *0x200b12(%rip) # 200ff8 <__cxa_finalize@GLIBC_2.2.5> 27 | 4e6: 66 90 xchg %ax,%ax 28 | 29 | Disassembly of section .text: 30 | 31 | 00000000000004f0
: 32 | 4f0: 31 c0 xor %eax,%eax 33 | 4f2: c3 retq 34 | 4f3: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 35 | 4fa: 00 00 00 36 | 4fd: 0f 1f 00 nopl (%rax) 37 | 38 | 0000000000000500 <_start>: 39 | 500: 31 ed xor %ebp,%ebp 40 | 502: 49 89 d1 mov %rdx,%r9 41 | 505: 5e pop %rsi 42 | 506: 48 89 e2 mov %rsp,%rdx 43 | 509: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 44 | 50d: 50 push %rax 45 | 50e: 54 push %rsp 46 | 50f: 4c 8d 05 6a 01 00 00 lea 0x16a(%rip),%r8 # 680 <__libc_csu_fini> 47 | 516: 48 8d 0d f3 00 00 00 lea 0xf3(%rip),%rcx # 610 <__libc_csu_init> 48 | 51d: 48 8d 3d cc ff ff ff lea -0x34(%rip),%rdi # 4f0
49 | 524: ff 15 b6 0a 20 00 callq *0x200ab6(%rip) # 200fe0 <__libc_start_main@GLIBC_2.2.5> 50 | 52a: f4 hlt 51 | 52b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) 52 | 53 | 0000000000000530 : 54 | 530: 48 8d 3d d9 0a 20 00 lea 0x200ad9(%rip),%rdi # 201010 <__TMC_END__> 55 | 537: 55 push %rbp 56 | 538: 48 8d 05 d1 0a 20 00 lea 0x200ad1(%rip),%rax # 201010 <__TMC_END__> 57 | 53f: 48 39 f8 cmp %rdi,%rax 58 | 542: 48 89 e5 mov %rsp,%rbp 59 | 545: 74 19 je 560 60 | 547: 48 8b 05 8a 0a 20 00 mov 0x200a8a(%rip),%rax # 200fd8 <_ITM_deregisterTMCloneTable> 61 | 54e: 48 85 c0 test %rax,%rax 62 | 551: 74 0d je 560 63 | 553: 5d pop %rbp 64 | 554: ff e0 jmpq *%rax 65 | 556: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 66 | 55d: 00 00 00 67 | 560: 5d pop %rbp 68 | 561: c3 retq 69 | 562: 0f 1f 40 00 nopl 0x0(%rax) 70 | 566: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 71 | 56d: 00 00 00 72 | 73 | 0000000000000570 : 74 | 570: 48 8d 3d 99 0a 20 00 lea 0x200a99(%rip),%rdi # 201010 <__TMC_END__> 75 | 577: 48 8d 35 92 0a 20 00 lea 0x200a92(%rip),%rsi # 201010 <__TMC_END__> 76 | 57e: 55 push %rbp 77 | 57f: 48 29 fe sub %rdi,%rsi 78 | 582: 48 89 e5 mov %rsp,%rbp 79 | 585: 48 c1 fe 03 sar $0x3,%rsi 80 | 589: 48 89 f0 mov %rsi,%rax 81 | 58c: 48 c1 e8 3f shr $0x3f,%rax 82 | 590: 48 01 c6 add %rax,%rsi 83 | 593: 48 d1 fe sar %rsi 84 | 596: 74 18 je 5b0 85 | 598: 48 8b 05 51 0a 20 00 mov 0x200a51(%rip),%rax # 200ff0 <_ITM_registerTMCloneTable> 86 | 59f: 48 85 c0 test %rax,%rax 87 | 5a2: 74 0c je 5b0 88 | 5a4: 5d pop %rbp 89 | 5a5: ff e0 jmpq *%rax 90 | 5a7: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) 91 | 5ae: 00 00 92 | 5b0: 5d pop %rbp 93 | 5b1: c3 retq 94 | 5b2: 0f 1f 40 00 nopl 0x0(%rax) 95 | 5b6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 96 | 5bd: 00 00 00 97 | 98 | 00000000000005c0 <__do_global_dtors_aux>: 99 | 5c0: 80 3d 49 0a 20 00 00 cmpb $0x0,0x200a49(%rip) # 201010 <__TMC_END__> 100 | 5c7: 75 2f jne 5f8 <__do_global_dtors_aux+0x38> 101 | 5c9: 48 83 3d 27 0a 20 00 cmpq $0x0,0x200a27(%rip) # 200ff8 <__cxa_finalize@GLIBC_2.2.5> 102 | 5d0: 00 103 | 5d1: 55 push %rbp 104 | 5d2: 48 89 e5 mov %rsp,%rbp 105 | 5d5: 74 0c je 5e3 <__do_global_dtors_aux+0x23> 106 | 5d7: 48 8b 3d 2a 0a 20 00 mov 0x200a2a(%rip),%rdi # 201008 <__dso_handle> 107 | 5de: e8 fd fe ff ff callq 4e0 <__cxa_finalize@plt> 108 | 5e3: e8 48 ff ff ff callq 530 109 | 5e8: c6 05 21 0a 20 00 01 movb $0x1,0x200a21(%rip) # 201010 <__TMC_END__> 110 | 5ef: 5d pop %rbp 111 | 5f0: c3 retq 112 | 5f1: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 113 | 5f8: f3 c3 repz retq 114 | 5fa: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 115 | 116 | 0000000000000600 : 117 | 600: 55 push %rbp 118 | 601: 48 89 e5 mov %rsp,%rbp 119 | 604: 5d pop %rbp 120 | 605: e9 66 ff ff ff jmpq 570 121 | 60a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 122 | 123 | 0000000000000610 <__libc_csu_init>: 124 | 610: 41 57 push %r15 125 | 612: 41 56 push %r14 126 | 614: 49 89 d7 mov %rdx,%r15 127 | 617: 41 55 push %r13 128 | 619: 41 54 push %r12 129 | 61b: 4c 8d 25 ce 07 20 00 lea 0x2007ce(%rip),%r12 # 200df0 <__frame_dummy_init_array_entry> 130 | 622: 55 push %rbp 131 | 623: 48 8d 2d ce 07 20 00 lea 0x2007ce(%rip),%rbp # 200df8 <__init_array_end> 132 | 62a: 53 push %rbx 133 | 62b: 41 89 fd mov %edi,%r13d 134 | 62e: 49 89 f6 mov %rsi,%r14 135 | 631: 4c 29 e5 sub %r12,%rbp 136 | 634: 48 83 ec 08 sub $0x8,%rsp 137 | 638: 48 c1 fd 03 sar $0x3,%rbp 138 | 63c: e8 77 fe ff ff callq 4b8 <_init> 139 | 641: 48 85 ed test %rbp,%rbp 140 | 644: 74 20 je 666 <__libc_csu_init+0x56> 141 | 646: 31 db xor %ebx,%ebx 142 | 648: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1) 143 | 64f: 00 144 | 650: 4c 89 fa mov %r15,%rdx 145 | 653: 4c 89 f6 mov %r14,%rsi 146 | 656: 44 89 ef mov %r13d,%edi 147 | 659: 41 ff 14 dc callq *(%r12,%rbx,8) 148 | 65d: 48 83 c3 01 add $0x1,%rbx 149 | 661: 48 39 dd cmp %rbx,%rbp 150 | 664: 75 ea jne 650 <__libc_csu_init+0x40> 151 | 666: 48 83 c4 08 add $0x8,%rsp 152 | 66a: 5b pop %rbx 153 | 66b: 5d pop %rbp 154 | 66c: 41 5c pop %r12 155 | 66e: 41 5d pop %r13 156 | 670: 41 5e pop %r14 157 | 672: 41 5f pop %r15 158 | 674: c3 retq 159 | 675: 90 nop 160 | 676: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 161 | 67d: 00 00 00 162 | 163 | 0000000000000680 <__libc_csu_fini>: 164 | 680: f3 c3 repz retq 165 | 166 | Disassembly of section .fini: 167 | 168 | 0000000000000684 <_fini>: 169 | 684: 48 83 ec 08 sub $0x8,%rsp 170 | 688: 48 83 c4 08 add $0x8,%rsp 171 | 68c: c3 retq 172 | -------------------------------------------------------------------------------- /CodeInSlides/chapter5/Measure-ALU-broken-simplified.c: -------------------------------------------------------------------------------- 1 | #define RUN_TIMES 1000000000 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | { 6 | int A=17, B=13, C=0; 7 | int i; 8 | for(i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define RUN_TIMES 1000000000 11 | 12 | double time_diff(struct timeval x , struct timeval y) 13 | { 14 | double x_ms , y_ms , diff; 15 | x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; 16 | y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; 17 | diff = (double)y_ms - (double)x_ms; 18 | return diff; 19 | } 20 | 21 | int main(int argc, char *argv[]) 22 | { 23 | { 24 | int A=17, B=13, C=0; 25 | int i; 26 | struct timeval tvStart,tvEnd; 27 | gettimeofday(&tvStart,NULL); 28 | for(i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define RUN_TIMES 1000000000 11 | 12 | double time_diff(struct timeval x , struct timeval y) 13 | { 14 | double x_ms , y_ms , diff; 15 | x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; 16 | y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; 17 | diff = (double)y_ms - (double)x_ms; 18 | return diff; 19 | } 20 | 21 | int main(int argc, char *argv[]) 22 | { 23 | { 24 | int A=17, B=13; 25 | int i; 26 | struct timeval tvStart,tvEnd; 27 | gettimeofday(&tvStart,NULL); 28 | for(i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define RUN_TIMES 50000 12 | 13 | sem_t fullSem; 14 | sem_t emptySem; 15 | 16 | pthread_mutex_t testMutex=PTHREAD_MUTEX_INITIALIZER; 17 | 18 | double time_diff(struct timeval x , struct timeval y) 19 | { 20 | double x_ms , y_ms , diff; 21 | x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; 22 | y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; 23 | diff = (double)y_ms - (double)x_ms; 24 | return diff; 25 | } 26 | 27 | typedef struct { 28 | double timeElapsed; 29 | } ThreadParas; 30 | 31 | void* threadAdd(void* args) { 32 | ThreadParas* para = (ThreadParas*) args; 33 | struct timeval tvStart,tvEnd; 34 | gettimeofday(&tvStart,NULL); 35 | for(int i=0;itimeElapsed=time_diff(tvStart,tvEnd); 44 | } 45 | 46 | void* threadSub(void* args) { 47 | ThreadParas* para = (ThreadParas*) args; 48 | struct timeval tvStart,tvEnd; 49 | gettimeofday(&tvStart,NULL); 50 | for(int i=0;itimeElapsed=time_diff(tvStart,tvEnd); 59 | } 60 | 61 | int main(int argc, char *argv[]) 62 | { 63 | { 64 | sem_destroy(&fullSem); 65 | sem_destroy(&emptySem); 66 | sem_init(&fullSem, 0, RUN_TIMES); 67 | sem_init(&emptySem, 0, RUN_TIMES); 68 | pthread_t th[2]; 69 | ThreadParas thPara[2]; 70 | if(pthread_create(&th[0], NULL, threadAdd, &thPara[0])!=0) 71 | { 72 | perror("pthread_create failed"); 73 | exit(1); 74 | } 75 | pthread_join(th[0], NULL); 76 | if(pthread_create(&th[1], NULL, threadSub, &thPara[1])!=0) 77 | { 78 | perror("pthread_create failed"); 79 | exit(1); 80 | } 81 | pthread_join(th[1], NULL); 82 | double totalTime=0; 83 | for(int i=0;i<2;i++) 84 | totalTime=totalTime+thPara[i].timeElapsed; 85 | double avgDelay=totalTime/2/RUN_TIMES; 86 | printf("[semaphore + mutex] Total time %.3lf s, Average time is %.5lf us\n",totalTime/1E6,avgDelay); 87 | } 88 | 89 | { 90 | sem_destroy(&fullSem); 91 | sem_destroy(&emptySem); 92 | sem_init(&fullSem, 0, 0); 93 | sem_init(&emptySem, 0, 1); 94 | pthread_t th[2]; 95 | ThreadParas thPara[2]; 96 | if(pthread_create(&th[0], NULL, threadAdd, &thPara[0])!=0) 97 | { 98 | perror("pthread_create failed"); 99 | exit(1); 100 | } 101 | if(pthread_create(&th[1], NULL, threadSub, &thPara[1])!=0) 102 | { 103 | perror("pthread_create failed"); 104 | exit(1); 105 | } 106 | for(int i=0;i<2;i++) 107 | pthread_join(th[i], NULL); 108 | 109 | double totalTime=0; 110 | for(int i=0;i<2;i++) 111 | totalTime=totalTime+thPara[i].timeElapsed; 112 | double avgDelay=totalTime/2/RUN_TIMES; 113 | printf("[semaphore + mutex + context switch] Total time %.3lf s, Average time is %.5lf us\n",totalTime/1E6,avgDelay); 114 | } 115 | 116 | exit(0); 117 | } -------------------------------------------------------------------------------- /CodeInSlides/chapter5/Measure-mutex-syscall.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define RUN_TIMES 100000000 11 | 12 | pthread_mutex_t testMutex=PTHREAD_MUTEX_INITIALIZER; 13 | 14 | double time_diff(struct timeval x , struct timeval y) 15 | { 16 | double x_ms , y_ms , diff; 17 | x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; 18 | y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; 19 | diff = (double)y_ms - (double)x_ms; 20 | return diff; 21 | } 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | struct timeval tvStart,tvEnd; 26 | gettimeofday(&tvStart,NULL); 27 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define RUN_TIMES 100000 11 | 12 | pthread_mutex_t testMutex=PTHREAD_MUTEX_INITIALIZER; 13 | 14 | double time_diff(struct timeval x , struct timeval y) 15 | { 16 | double x_ms , y_ms , diff; 17 | x_ms = (double)x.tv_sec*1000000 + (double)x.tv_usec; 18 | y_ms = (double)y.tv_sec*1000000 + (double)y.tv_usec; 19 | diff = (double)y_ms - (double)x_ms; 20 | return diff; 21 | } 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | struct timeval tvStart,tvEnd; 26 | gettimeofday(&tvStart,NULL); 27 | for(int i=0;i thread.log 2 | sort -k 2 -n thread.log > result.log 3 | vi result.log 4 | rm thread*.log -------------------------------------------------------------------------------- /CodeInSlides/chapter7/HighConcurrent-client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define MAXIN 256 13 | #define MAXOUT 256 14 | 15 | void* client(void* args) { 16 | int* sockfdAddr=(int *) args; 17 | int sockfd=*sockfdAddr; 18 | int n; 19 | char sndbuf[MAXIN]; char rcvbuf[MAXOUT]; 20 | memset(sndbuf,0,MAXIN); 21 | memcpy(sndbuf,"Hello\n",sizeof("Hello\n")); 22 | int sleepseconds=rand()%100+100; //Sleep 10s~20s to emulate user input 23 | sleep(sleepseconds); 24 | n=write(sockfd, sndbuf, strlen(sndbuf)); /* send */ 25 | if (n <= 0) { 26 | perror("Error: write to socket"); 27 | close(sockfd); 28 | free(sockfdAddr); 29 | return NULL; 30 | } 31 | 32 | memset(rcvbuf,0,MAXOUT); /* clear */ 33 | n=read(sockfd, rcvbuf, MAXOUT-1); /* receive */ 34 | if (n <= 0) { 35 | perror("Error: read from socket"); 36 | close(sockfd); 37 | free(sockfdAddr); 38 | return NULL; 39 | } 40 | 41 | close(sockfd); 42 | free(sockfdAddr); 43 | return NULL; 44 | } 45 | 46 | int main(int argc, char *argv[]) 47 | { 48 | if(argc!=4) 49 | { 50 | printf("usage: %s destIP port MAX_CONN_NUM\n",argv[0]); 51 | exit(1); 52 | } 53 | int len; 54 | struct in_addr server_addr; 55 | if(!inet_aton(argv[1], &server_addr)) 56 | perror("inet_aton"); 57 | struct sockaddr_in remote_addr; 58 | char buf[BUFSIZ]; 59 | memset(&remote_addr,0,sizeof(remote_addr)); 60 | remote_addr.sin_family=AF_INET; 61 | remote_addr.sin_addr=server_addr; 62 | int port=atoi(argv[2]); 63 | remote_addr.sin_port=htons(port); 64 | int MAX_CONN_NUM=atoi(argv[3]); 65 | 66 | 67 | srand(time(NULL)); 68 | pthread_t *th=malloc(MAX_CONN_NUM*sizeof(pthread_t)); 69 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define MAXREQ 256 16 | #define MAX_EVENT 20 17 | #define READ_BUF_LEN 256 18 | 19 | int main(int argc, char *argv[]) 20 | { 21 | if(argc!=2) 22 | { 23 | printf("usage: %s port\n",argv[0]); 24 | return 1; 25 | } 26 | int port=atoi(argv[1]); 27 | 28 | // epoll 实例 file describe 29 | int epfd = 0; 30 | int listenfd = 0; 31 | int result = 0; 32 | struct epoll_event ev, event[MAX_EVENT]; 33 | // 绑定的地址 34 | 35 | struct sockaddr_in my_addr; 36 | my_addr.sin_family=AF_INET; 37 | my_addr.sin_addr.s_addr=INADDR_ANY; 38 | my_addr.sin_port=htons(port); 39 | 40 | listenfd = socket(AF_INET, SOCK_STREAM, 0); 41 | if (-1 == listenfd) { 42 | perror("Open listen socket"); 43 | return -1; 44 | } 45 | /* Enable address reuse */ 46 | int on = 1; 47 | // 打开 socket 端口复用, 防止测试的时候出现 Address already in use 48 | result = setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ); 49 | if (-1 == result) { 50 | perror ("Set socket"); 51 | return 0; 52 | } 53 | 54 | result = bind(listenfd, (const struct sockaddr *)&my_addr, sizeof (my_addr)); 55 | if (-1 == result) { 56 | perror("Bind port"); 57 | return 0; 58 | } 59 | 60 | result = listen(listenfd, 5); 61 | if (-1 == result) { 62 | perror("Start listen"); 63 | return 0; 64 | } 65 | 66 | // 创建epoll实例 67 | epfd = epoll_create1(0); 68 | if (1 == epfd) { 69 | perror("Create epoll instance"); 70 | return 0; 71 | } 72 | 73 | ev.data.fd = listenfd; 74 | ev.events = EPOLLIN; 75 | // 设置epoll的事件 76 | result = epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev); 77 | 78 | if(-1 == result) { 79 | perror("Set epoll_ctl"); 80 | return 0; 81 | } 82 | 83 | int inComeConnNum=0; 84 | while (1) { 85 | int wait_count; 86 | // 等待事件 87 | wait_count = epoll_wait(epfd, event, MAX_EVENT, -1); 88 | 89 | for (int i = 0 ; i < wait_count; i++) { 90 | uint32_t events = event[i].events; 91 | // IP地址缓存 92 | char host_buf[NI_MAXHOST]; 93 | // PORT缓存 94 | char port_buf[NI_MAXSERV]; 95 | 96 | int __result; 97 | // 判断epoll是否发生错误 98 | if ( events & EPOLLERR || events & EPOLLHUP || (! events & EPOLLIN)) { 99 | printf("Epoll has error\n"); 100 | close (event[i].data.fd); 101 | continue; 102 | } else if (listenfd == event[i].data.fd) { 103 | // listen的 file describe 事件触发, accpet事件 104 | struct sockaddr in_addr = { 0 }; 105 | socklen_t in_addr_len = sizeof (in_addr); 106 | int accp_fd = accept(listenfd, &in_addr, &in_addr_len); 107 | if (-1 == accp_fd) { 108 | perror("Accept"); 109 | continue; 110 | } 111 | __result = getnameinfo(&in_addr, sizeof (in_addr), 112 | host_buf, sizeof (host_buf) / sizeof (host_buf[0]), 113 | port_buf, sizeof (port_buf) / sizeof (port_buf[0]), 114 | NI_NUMERICHOST | NI_NUMERICSERV); 115 | 116 | if (! __result) { 117 | inComeConnNum++; 118 | printf("[%d connections accepted] from client %s:%s\n", inComeConnNum, host_buf, port_buf); 119 | } 120 | else { 121 | perror("Client address"); 122 | continue; 123 | } 124 | 125 | ev.data.fd = accp_fd; 126 | ev.events = EPOLLIN | EPOLLET; 127 | // 为新accept的 file describe 设置epoll事件 128 | __result = epoll_ctl(epfd, EPOLL_CTL_ADD, accp_fd, &ev); 129 | 130 | if (-1 == __result) { 131 | perror("epoll_ctl"); 132 | return 0; 133 | } 134 | } else { 135 | // 其余事件为 file describe 可以读取 136 | ssize_t result_len = 0; 137 | char buf[READ_BUF_LEN] = { 0 }; 138 | 139 | result_len = read(event[i].data.fd, buf, sizeof (buf) / sizeof (buf[0])); 140 | //Read client's request 141 | 142 | if (result_len <= 0) { 143 | perror ("Error: Read data"); 144 | } else { 145 | int n; 146 | // n=write(STDOUT_FILENO, buf, result_len); 147 | // fflush(stdout); 148 | n=write(event[i].data.fd, buf, result_len); 149 | //Echo client's request as response 150 | if (n <= 0) 151 | perror("Error: write to socket"); 152 | } 153 | // printf("Closed connection\n"); 154 | close (event[i].data.fd); 155 | } 156 | } 157 | } 158 | close (epfd); 159 | return 0; 160 | } -------------------------------------------------------------------------------- /CodeInSlides/chapter7/HighConcurrent-normal-server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define MAXREQ 256 13 | 14 | void* server(void* args) { 15 | int* consockfdAddr=(int *) args; 16 | int consockfd=*consockfdAddr; 17 | char reqbuf[MAXREQ]; 18 | int n; 19 | 20 | memset(reqbuf,0, MAXREQ); 21 | n = read(consockfd,reqbuf,MAXREQ-1); /* Recv request*/ 22 | if (n <= 0) { 23 | perror("Error: read from socket"); 24 | close(consockfd); 25 | free(consockfdAddr); 26 | return NULL; 27 | } 28 | // n=write(STDOUT_FILENO, reqbuf, strlen(reqbuf)); 29 | // fflush(stdout); 30 | n = write(consockfd, reqbuf, strlen(reqbuf)); /* echo as response*/ 31 | if (n <= 0) { 32 | perror("Error: write to socket"); 33 | close(consockfd); 34 | free(consockfdAddr); 35 | return NULL; 36 | } 37 | 38 | close(consockfd); 39 | free(consockfdAddr); 40 | return NULL; 41 | } 42 | 43 | 44 | int main(int argc, char *argv[]) 45 | { 46 | if(argc!=2) 47 | { 48 | printf("usage: %s port\n",argv[0]); 49 | return 1; 50 | } 51 | int port=atoi(argv[1]); 52 | 53 | struct sockaddr_in my_addr; 54 | my_addr.sin_family=AF_INET; 55 | my_addr.sin_addr.s_addr=INADDR_ANY; 56 | my_addr.sin_port=htons(port); 57 | 58 | int server_sockfd; 59 | if((server_sockfd=socket(AF_INET,SOCK_STREAM,0))<0) 60 | { 61 | perror("socket"); 62 | return 1; 63 | } 64 | 65 | int on=1; 66 | if((setsockopt(server_sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0) 67 | { 68 | perror("setsockopt failed"); 69 | return 1; 70 | } 71 | 72 | if (bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(my_addr))<0) 73 | { 74 | perror("bind"); 75 | return 1; 76 | } 77 | 78 | int sin_size=sizeof(struct sockaddr_in); 79 | struct sockaddr_in remote_addr; 80 | if(listen(server_sockfd,5)<0) 81 | { 82 | perror("listen"); 83 | return 1; 84 | } 85 | 86 | int inComeConnNum=0; 87 | while (1) { 88 | int *client_sockfd=malloc(sizeof(int)); 89 | if((*client_sockfd=accept(server_sockfd,(struct sockaddr *)&remote_addr,&sin_size))<0) 90 | { 91 | perror("Error: accept"); 92 | return 1; 93 | } 94 | inComeConnNum++; 95 | printf("[%d connections accepted] from client %s:%d\n",inComeConnNum,inet_ntoa(remote_addr.sin_addr),ntohs(remote_addr.sin_port)); 96 | 97 | pthread_t th; 98 | if(pthread_create(&th, NULL, server, client_sockfd)!=0) 99 | { 100 | perror("pthread_create failed"); 101 | exit(1); 102 | } 103 | 104 | } 105 | close(server_sockfd); 106 | 107 | return 0; 108 | } -------------------------------------------------------------------------------- /CodeInSlides/chapter7/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010 Benoit Sigoure 2 | # 3 | # This program is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program. If not, see . 15 | 16 | CC = gcc 17 | CFLAGS = -O2 -pthread 18 | 19 | # the build target executable: 20 | TARGETS = UDP-server UDP-client TCP-server TCP-client TCP-server-reliable TCP-client-reliable\ 21 | TCP-server-thread-send TCP-client-thread-send TCP-server-thread-recv TCP-client-thread-recv\ 22 | echo-server echo-client HighConcurrent-client HighConcurrent-normal-server HighConcurrent-epoll-server 23 | 24 | all: $(TARGETS) 25 | 26 | clean: 27 | $(RM) $(TARGETS) 28 | 29 | -------------------------------------------------------------------------------- /CodeInSlides/chapter7/TCP-client-reliable.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | typedef struct { 13 | int ID; 14 | int len; 15 | } DataInfo; 16 | 17 | int sendAllChunk(int sock, char* buf, int chunkSize) 18 | { 19 | int sentBytes=0; 20 | int len; 21 | while(1) { 22 | if(chunkSize-sentBytes==0)//This data chunk has all been sent 23 | break; 24 | len=send(sock,buf+sentBytes,chunkSize-sentBytes,0); 25 | if(len<0) 26 | { 27 | perror("TCP send"); 28 | return -1;//Error 29 | } 30 | sentBytes=sentBytes+len; 31 | } 32 | return 0;//Success 33 | } 34 | 35 | int recvAllChunk(int sock, char* buf, int chunkSize) 36 | { 37 | int receivedBytes=0; 38 | int len; 39 | while(1) { 40 | if(chunkSize-receivedBytes==0)//This data chunk has all been received 41 | break; 42 | len=recv(sock,buf+receivedBytes,chunkSize-receivedBytes,0); 43 | if(len<=0) { 44 | perror("TCP recv"); 45 | return -1;//Error 46 | } 47 | receivedBytes=receivedBytes+len; 48 | } 49 | return 0;//Success 50 | } 51 | 52 | void sendData(int sock, int sentTimes) 53 | { 54 | char bufSent[BUFSIZ]; 55 | int totalSentTimes=0; 56 | int bytesToSend=0; 57 | int totalSentBytes=0; 58 | while(1) 59 | { 60 | usleep(1000); 61 | if(totalSentTimes>=sentTimes) 62 | break; 63 | memset(bufSent,0,BUFSIZ*sizeof(bufSent[0])); 64 | sprintf(bufSent,"*%07d*",totalSentTimes); 65 | bytesToSend=strlen(bufSent); 66 | 67 | if(sendAllChunk(sock,bufSent,bytesToSend)==-1) 68 | exit(1); 69 | 70 | printf("[%7d, %9d] Sent: ",totalSentTimes,totalSentBytes); 71 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define REQUEST_PADDING_SIZE 10240 13 | 14 | typedef struct { 15 | int threadID; 16 | int requestID; 17 | char padding[REQUEST_PADDING_SIZE]; 18 | } RequestInfo; 19 | 20 | int sendAllChunk(int sock, char* buf, int chunkSize) 21 | { 22 | int sentBytes=0; 23 | int len; 24 | while(1) { 25 | if(chunkSize-sentBytes==0)//This data chunk has all been sent 26 | break; 27 | // len=write(sock,buf+sentBytes,chunkSize-sentBytes); 28 | len=send(sock,buf+sentBytes,chunkSize-sentBytes,0); 29 | if(len<0) 30 | { 31 | perror("TCP send"); 32 | return -1;//Error 33 | } 34 | sentBytes=sentBytes+len; 35 | } 36 | return 0;//Success 37 | } 38 | 39 | int recvAllChunk(int sock, char* buf, int chunkSize) 40 | { 41 | int receivedBytes=0; 42 | int len; 43 | while(1) { 44 | if(chunkSize-receivedBytes==0)//This data chunk has all been received 45 | break; 46 | // len=read(sock,buf+receivedBytes,chunkSize-receivedBytes); 47 | len=recv(sock,buf+receivedBytes,chunkSize-receivedBytes,0); 48 | if(len<=0) { 49 | perror("TCP recv"); 50 | return -1;//Error 51 | } 52 | receivedBytes=receivedBytes+len; 53 | } 54 | return 0;//Success 55 | } 56 | 57 | int main(int argc, char *argv[]) 58 | { 59 | if(argc!=4) 60 | { 61 | printf("usage: %s destIP port requestNum\n",argv[0]); 62 | exit(1); 63 | } 64 | int client_sockfd; 65 | int len; 66 | struct in_addr server_addr; 67 | if(!inet_aton(argv[1], &server_addr)) 68 | perror("inet_aton"); 69 | struct sockaddr_in remote_addr; 70 | memset(&remote_addr,0,sizeof(remote_addr)); 71 | remote_addr.sin_family=AF_INET; 72 | remote_addr.sin_addr=server_addr; 73 | int port=atoi(argv[2]); 74 | remote_addr.sin_port=htons(port); 75 | int requestNum=atoi(argv[3]); 76 | 77 | if((client_sockfd=socket(AF_INET,SOCK_STREAM,0))<0) 78 | { 79 | perror("socket"); 80 | return 1; 81 | } 82 | 83 | if(connect(client_sockfd,(const struct sockaddr *)&remote_addr,sizeof(remote_addr))<0) 84 | { 85 | perror("connect"); 86 | return 1; 87 | } 88 | printf("connected to server %s\n",inet_ntoa(remote_addr.sin_addr)); 89 | 90 | RequestInfo dInfo; 91 | memset(dInfo.padding,'A',REQUEST_PADDING_SIZE); 92 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define REQUEST_PADDING_SIZE 10240 13 | 14 | typedef struct { 15 | int threadID; 16 | int requestID; 17 | char padding[REQUEST_PADDING_SIZE]; 18 | } RequestInfo; 19 | 20 | int sendAllChunk(int sock, char* buf, int chunkSize) 21 | { 22 | int sentBytes=0; 23 | int len; 24 | while(1) { 25 | if(chunkSize-sentBytes==0)//This data chunk has all been sent 26 | break; 27 | // len=write(sock,buf+sentBytes,chunkSize-sentBytes); 28 | len=send(sock,buf+sentBytes,chunkSize-sentBytes,0); 29 | if(len<0) 30 | { 31 | perror("TCP send"); 32 | return -1;//Error 33 | } 34 | sentBytes=sentBytes+len; 35 | } 36 | return 0;//Success 37 | } 38 | 39 | int recvAllChunk(int sock, char* buf, int chunkSize) 40 | { 41 | int receivedBytes=0; 42 | int len; 43 | while(1) { 44 | if(chunkSize-receivedBytes==0)//This data chunk has all been received 45 | break; 46 | // len=read(sock,buf+receivedBytes,chunkSize-receivedBytes); 47 | len=recv(sock,buf+receivedBytes,chunkSize-receivedBytes,0); 48 | if(len<=0) { 49 | perror("TCP recv"); 50 | return -1;//Error 51 | } 52 | receivedBytes=receivedBytes+len; 53 | } 54 | return 0;//Success 55 | } 56 | 57 | void recvRequest(int sock, int requestNum) 58 | { 59 | char fileName[128]={0}; 60 | sprintf(fileName,"thread%03d.log",0); 61 | FILE *fp; 62 | if((fp = fopen(fileName,"w"))==NULL) 63 | { 64 | perror("fopen ERROR!"); 65 | exit(1); 66 | } 67 | int totalRequestNum=0; 68 | RequestInfo* dInfo=malloc(requestNum*sizeof(RequestInfo)); 69 | while(1) { 70 | if(recvAllChunk(sock,(char*)&(dInfo[totalRequestNum]),sizeof(RequestInfo))==-1) 71 | break; 72 | totalRequestNum++; 73 | } 74 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define MAX_DATAGRAM_SIZE 1400 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | if(argc!=4) 17 | { 18 | printf("usage: %s destIP port sentTimes\n",argv[0]); 19 | exit(1); 20 | } 21 | int client_sockfd; 22 | int len; 23 | struct in_addr server_addr; 24 | if(!inet_aton(argv[1], &server_addr)) 25 | perror("inet_aton"); 26 | struct sockaddr_in remote_addr; 27 | char buf[BUFSIZ]; 28 | memset(&remote_addr,0,sizeof(remote_addr)); 29 | remote_addr.sin_family=AF_INET; 30 | remote_addr.sin_addr=server_addr; 31 | int port=atoi(argv[2]); 32 | remote_addr.sin_port=htons(port); 33 | int sentTimes=atoi(argv[3]); 34 | 35 | if((client_sockfd=socket(AF_INET,SOCK_STREAM,0))<0) 36 | { 37 | perror("socket"); 38 | return 1; 39 | } 40 | 41 | if(connect(client_sockfd,(const struct sockaddr *)&remote_addr,sizeof(remote_addr))<0) 42 | { 43 | perror("connect"); 44 | return 1; 45 | } 46 | printf("connected to server %s\n",inet_ntoa(remote_addr.sin_addr)); 47 | 48 | char bufSent[MAX_DATAGRAM_SIZE]; 49 | int totalSentTimes=0; 50 | int bytesToSend=0; 51 | int totalSentBytes=0; 52 | while(1) 53 | { 54 | usleep(1000); 55 | if(totalSentTimes>=sentTimes) 56 | break; 57 | memset(bufSent,0,MAX_DATAGRAM_SIZE*sizeof(bufSent[0])); 58 | sprintf(bufSent,"*%07d*",totalSentTimes); 59 | bytesToSend=strlen(bufSent); 60 | if(send(client_sockfd,bufSent,bytesToSend,0)<0) 61 | { 62 | perror("TCP send"); 63 | return 1; 64 | } 65 | 66 | printf("[%7d, %9d] Sent: ",totalSentTimes,totalSentBytes); 67 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | typedef struct { 13 | int ID; 14 | int len; 15 | } DataInfo; 16 | 17 | int sendAllChunk(int sock, char* buf, int chunkSize) 18 | { 19 | int sentBytes=0; 20 | int len; 21 | while(1) { 22 | if(chunkSize-sentBytes==0)//This data chunk has all been sent 23 | break; 24 | len=send(sock,buf+sentBytes,chunkSize-sentBytes,0); 25 | if(len<0) 26 | { 27 | perror("TCP send"); 28 | return -1;//Error 29 | } 30 | sentBytes=sentBytes+len; 31 | } 32 | return 0;//Success 33 | } 34 | 35 | int recvAllChunk(int sock, char* buf, int chunkSize) 36 | { 37 | int receivedBytes=0; 38 | int len; 39 | while(1) { 40 | if(chunkSize-receivedBytes==0)//This data chunk has all been received 41 | break; 42 | len=recv(sock,buf+receivedBytes,chunkSize-receivedBytes,0); 43 | if(len<=0) { 44 | perror("TCP recv"); 45 | return -1;//Error 46 | } 47 | receivedBytes=receivedBytes+len; 48 | } 49 | return 0;//Success 50 | } 51 | 52 | void receiveData(int sock, int bytesToReceive) 53 | { 54 | int totalReceivedBytes=0; 55 | int totalReceivedTimes=0; 56 | char buf[BUFSIZ]; 57 | int chunkSize; 58 | while(1) 59 | { 60 | if(totalReceivedBytes>=bytesToReceive) 61 | break; 62 | if(bytesToReceive-totalReceivedBytes>=BUFSIZ) 63 | chunkSize=BUFSIZ; 64 | else 65 | chunkSize=bytesToReceive-totalReceivedBytes; 66 | if(recvAllChunk(sock,buf,chunkSize)==-1) 67 | exit(1); 68 | 69 | printf("[%7d, %9d] Received: ",totalReceivedTimes,totalReceivedBytes); 70 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define REQUEST_BUFFER_ALLOC_STEP 10000 13 | #define REQUEST_PADDING_SIZE 10240 14 | 15 | typedef struct { 16 | int threadID; 17 | int sock; 18 | int receivedNum; 19 | } ThreadParas; 20 | 21 | typedef struct { 22 | int threadID; 23 | int requestID; 24 | char padding[REQUEST_PADDING_SIZE]; 25 | } RequestInfo; 26 | 27 | int sendAllChunk(int sock, char* buf, int chunkSize) 28 | { 29 | int sentBytes=0; 30 | int len; 31 | while(1) { 32 | if(chunkSize-sentBytes==0)//This data chunk has all been sent 33 | break; 34 | // len=write(sock,buf+sentBytes,chunkSize-sentBytes); 35 | len=send(sock,buf+sentBytes,chunkSize-sentBytes,0); 36 | if(len<0) 37 | { 38 | perror("TCP send"); 39 | return -1;//Error 40 | } 41 | sentBytes=sentBytes+len; 42 | } 43 | return 0;//Success 44 | } 45 | 46 | int recvAllChunk(int sock, char* buf, int chunkSize) 47 | { 48 | int receivedBytes=0; 49 | int len; 50 | while(1) { 51 | if(chunkSize-receivedBytes==0)//This data chunk has all been received 52 | break; 53 | // len=read(sock,buf+receivedBytes,chunkSize-receivedBytes); 54 | len=recv(sock,buf+receivedBytes,chunkSize-receivedBytes,0); 55 | if(len<=0) { 56 | perror("TCP recv"); 57 | return -1;//Error 58 | } 59 | receivedBytes=receivedBytes+len; 60 | } 61 | return 0;//Success 62 | } 63 | 64 | void* recvRequest(void* args) 65 | { 66 | ThreadParas* para = (ThreadParas*) args; 67 | int threadID=para->threadID; 68 | int sock=para->sock; 69 | 70 | char fileName[128]={0}; 71 | sprintf(fileName,"thread%03d.log",threadID); 72 | FILE *fp; 73 | if((fp = fopen(fileName,"w"))==NULL) 74 | { 75 | perror("fopen ERROR!"); 76 | exit(1); 77 | } 78 | int totalRequestNum=0; 79 | int requestBufferLen=REQUEST_BUFFER_ALLOC_STEP; 80 | RequestInfo* dInfo=malloc(REQUEST_BUFFER_ALLOC_STEP*sizeof(RequestInfo)); 81 | while(1) { 82 | if(recvAllChunk(sock,(char*)&(dInfo[totalRequestNum]),sizeof(RequestInfo))==-1) 83 | break; 84 | totalRequestNum++; 85 | if(totalRequestNum==requestBufferLen)//Expand receive buffer 86 | { 87 | printf("(thread %3d) Realloc receive buffer: current len %d, expand %d\n",threadID,requestBufferLen,REQUEST_BUFFER_ALLOC_STEP); 88 | requestBufferLen += REQUEST_BUFFER_ALLOC_STEP; 89 | RequestInfo* myrealloced_dInfo = realloc(dInfo, requestBufferLen * sizeof(RequestInfo)); 90 | if (myrealloced_dInfo) { 91 | dInfo = myrealloced_dInfo; 92 | } else { 93 | perror("Expand receive buffer failure"); 94 | exit(1); 95 | } 96 | } 97 | } 98 | for(int i=0;ireceivedNum=totalRequestNum; 107 | printf("(thread %3d) Received %d requests!\n",threadID,totalRequestNum); 108 | return NULL; 109 | } 110 | 111 | 112 | int main(int argc, char *argv[]) 113 | { 114 | if(argc!=3) 115 | { 116 | printf("usage: %s port threadNum\n",argv[0]); 117 | return 1; 118 | } 119 | int port=atoi(argv[1]); 120 | int threadNum=atoi(argv[2]); 121 | 122 | struct sockaddr_in my_addr; 123 | my_addr.sin_family=AF_INET; 124 | my_addr.sin_addr.s_addr=INADDR_ANY; 125 | my_addr.sin_port=htons(port); 126 | 127 | int server_sockfd; 128 | int client_sockfd; 129 | if((server_sockfd=socket(AF_INET,SOCK_STREAM,0))<0) 130 | { 131 | perror("socket"); 132 | return 1; 133 | } 134 | 135 | int on=1; 136 | if((setsockopt(server_sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0) 137 | { 138 | perror("setsockopt failed"); 139 | return 1; 140 | } 141 | 142 | if (bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(my_addr))<0) 143 | { 144 | perror("bind"); 145 | return 1; 146 | } 147 | 148 | int sin_size=sizeof(struct sockaddr_in); 149 | struct sockaddr_in remote_addr; 150 | listen(server_sockfd,5); 151 | if((client_sockfd=accept(server_sockfd,(struct sockaddr *)&remote_addr,&sin_size))<0) 152 | { 153 | perror("Error: accept"); 154 | return 1; 155 | } 156 | printf("accept client %s\n",inet_ntoa(remote_addr.sin_addr)); 157 | 158 | 159 | pthread_t th[threadNum]; 160 | ThreadParas para[threadNum]; 161 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define REQUEST_PADDING_SIZE 10240 13 | 14 | typedef struct { 15 | int threadID; 16 | int requestID; 17 | char padding[REQUEST_PADDING_SIZE]; 18 | } RequestInfo; 19 | 20 | typedef struct { 21 | int threadID; 22 | int sentRequestNum; 23 | int sock; 24 | } ThreadParas; 25 | 26 | int sendAllChunk(int sock, char* buf, int chunkSize) 27 | { 28 | int sentBytes=0; 29 | int len; 30 | while(1) { 31 | if(chunkSize-sentBytes==0)//This data chunk has all been sent 32 | break; 33 | // len=write(sock,buf+sentBytes,chunkSize-sentBytes); 34 | len=send(sock,buf+sentBytes,chunkSize-sentBytes,0); 35 | if(len<0) 36 | { 37 | perror("TCP send"); 38 | return -1;//Error 39 | } 40 | sentBytes=sentBytes+len; 41 | } 42 | return 0;//Success 43 | } 44 | 45 | int recvAllChunk(int sock, char* buf, int chunkSize) 46 | { 47 | int receivedBytes=0; 48 | int len; 49 | while(1) { 50 | if(chunkSize-receivedBytes==0)//This data chunk has all been received 51 | break; 52 | // len=read(sock,buf+receivedBytes,chunkSize-receivedBytes); 53 | len=recv(sock,buf+receivedBytes,chunkSize-receivedBytes,0); 54 | if(len<=0) { 55 | perror("TCP recv"); 56 | return -1;//Error 57 | } 58 | receivedBytes=receivedBytes+len; 59 | } 60 | return 0;//Success 61 | } 62 | 63 | void* sendRequest(void* args) 64 | { 65 | ThreadParas* para = (ThreadParas*) args; 66 | int sentRequestNum=para->sentRequestNum; 67 | int threadID=para->threadID; 68 | int sock=para->sock; 69 | 70 | RequestInfo dInfo; 71 | memset(dInfo.padding,'A',REQUEST_PADDING_SIZE); 72 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | if(argc!=2) 15 | { 16 | printf("usage: %s port\n",argv[0]); 17 | return 1; 18 | } 19 | int port=atoi(argv[1]); 20 | 21 | struct sockaddr_in my_addr; 22 | my_addr.sin_family=AF_INET; 23 | my_addr.sin_addr.s_addr=INADDR_ANY; 24 | my_addr.sin_port=htons(port); 25 | 26 | int server_sockfd; 27 | int client_sockfd; 28 | if((server_sockfd=socket(AF_INET,SOCK_STREAM,0))<0) 29 | { 30 | perror("socket"); 31 | return 1; 32 | } 33 | 34 | int on=1; 35 | if((setsockopt(server_sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0) 36 | { 37 | perror("setsockopt failed"); 38 | return 1; 39 | } 40 | 41 | if (bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(my_addr))<0) 42 | { 43 | perror("bind"); 44 | return 1; 45 | } 46 | 47 | int sin_size=sizeof(struct sockaddr_in); 48 | struct sockaddr_in remote_addr; 49 | listen(server_sockfd,5); 50 | if((client_sockfd=accept(server_sockfd,(struct sockaddr *)&remote_addr,&sin_size))<0) 51 | { 52 | perror("Error: accept"); 53 | return 1; 54 | } 55 | printf("accept client %s\n",inet_ntoa(remote_addr.sin_addr)); 56 | 57 | char buf[BUFSIZ]; 58 | int totalReceivedTimes=0; 59 | int len=0; 60 | int totalReceivedBytes=0; 61 | while(1) 62 | { 63 | // usleep(1000); 64 | memset(buf,0,BUFSIZ*sizeof(buf[0])); 65 | len = recv(client_sockfd,buf,BUFSIZ,0); 66 | if(len<0) 67 | { 68 | printf("recvfrom failed!\n"); 69 | break; 70 | } 71 | if(len==0) 72 | { 73 | printf("recvfrom done!\n"); 74 | break; 75 | } 76 | 77 | printf("[%7d, %9d] Received: ",totalReceivedTimes,totalReceivedBytes); 78 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define MAX_DATAGRAM_SIZE 1400 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | if(argc!=4) 17 | { 18 | printf("usage: %s destIP port sentTimes\n",argv[0]); 19 | exit(1); 20 | } 21 | int client_sockfd; 22 | int len; 23 | struct in_addr server_addr; 24 | if(!inet_aton(argv[1], &server_addr)) 25 | perror("inet_aton"); 26 | struct sockaddr_in remote_addr; 27 | char buf[BUFSIZ]; 28 | memset(&remote_addr,0,sizeof(remote_addr)); 29 | remote_addr.sin_family=AF_INET; 30 | remote_addr.sin_addr=server_addr; 31 | int port=atoi(argv[2]); 32 | remote_addr.sin_port=htons(port); 33 | int sentTimes=atoi(argv[3]); 34 | 35 | if((client_sockfd=socket(AF_INET,SOCK_DGRAM,0))<0) 36 | { 37 | perror("socket"); 38 | return 1; 39 | } 40 | 41 | char bufSent[MAX_DATAGRAM_SIZE]; 42 | int totalSentTimes=0; 43 | int bytesToSend=0; 44 | int totalSentBytes=0; 45 | while(1) 46 | { 47 | usleep(1000); 48 | if(totalSentTimes>=sentTimes) 49 | break; 50 | memset(bufSent,0,MAX_DATAGRAM_SIZE*sizeof(bufSent[0])); 51 | sprintf(bufSent,"*%d*",totalSentTimes); 52 | bytesToSend=strlen(bufSent); 53 | sendto(client_sockfd,bufSent,bytesToSend,0,(struct sockaddr*)&remote_addr,sizeof(remote_addr)); 54 | 55 | printf("[%4d, %8d] Sent: ",totalSentTimes,totalSentBytes); 56 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | if(argc!=2) 15 | { 16 | printf("usage: %s port\n",argv[0]); 17 | return 1; 18 | } 19 | int port=atoi(argv[1]); 20 | 21 | struct sockaddr_in my_addr; 22 | my_addr.sin_family=AF_INET; 23 | my_addr.sin_addr.s_addr=INADDR_ANY; 24 | my_addr.sin_port=htons(port); 25 | 26 | int server_sockfd;//UDP server socket 27 | if((server_sockfd=socket(AF_INET,SOCK_DGRAM,0))<0) 28 | { 29 | perror("socket"); 30 | return 1; 31 | } 32 | 33 | if (bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(my_addr))<0) 34 | { 35 | perror("bind"); 36 | return 1; 37 | } 38 | 39 | char buf[BUFSIZ]; 40 | int totalReceivedTimes=0; 41 | int len=0; 42 | int totalReceivedBytes=0; 43 | while(1) 44 | { 45 | // usleep(1000); 46 | memset(buf,0,BUFSIZ*sizeof(buf[0])); 47 | len = recvfrom(server_sockfd,buf,BUFSIZ,0,NULL,NULL); 48 | if(len<0) 49 | { 50 | printf("recvfrom failed!\n"); 51 | break; 52 | } 53 | 54 | printf("[%4d, %8d] Received: ",totalReceivedTimes,totalReceivedBytes); 55 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define MAXIN 256 13 | #define MAXOUT 256 14 | #define MAX_THREAD_NUM 8092 15 | 16 | char *getreq(char *inbuf, int len) { 17 | /* Get request char stream */ 18 | // printf("REQ: "); /* prompt */ 19 | memset(inbuf,0,len); /* clear for good measure */ 20 | return fgets(inbuf,len,stdin); /* read up to a EOL */ 21 | } 22 | 23 | 24 | void* client(void* args) { 25 | int* sockfdAddr=(int *) args; 26 | int sockfd=*sockfdAddr; 27 | int n; 28 | char sndbuf[MAXIN]; char rcvbuf[MAXOUT]; 29 | getreq(sndbuf, MAXIN); /* prompt */ 30 | while (strlen(sndbuf) > 0) { 31 | n=write(sockfd, sndbuf, strlen(sndbuf)); /* send */ 32 | if (n <= 0) { 33 | perror("Error: write to socket"); 34 | close(sockfd); 35 | free(sockfdAddr); 36 | return NULL; 37 | } 38 | memset(rcvbuf,0,MAXOUT); /* clear */ 39 | n=read(sockfd, rcvbuf, MAXOUT-1); /* receive */ 40 | if (n <= 0) { 41 | perror("Error: read from socket"); 42 | close(sockfd); 43 | free(sockfdAddr); 44 | return NULL; 45 | } 46 | n=write(STDOUT_FILENO, rcvbuf, n); /* echo */ 47 | getreq(sndbuf, MAXIN); /* prompt */ 48 | } 49 | close(sockfd); 50 | free(sockfdAddr); 51 | return NULL; 52 | } 53 | 54 | int main(int argc, char *argv[]) 55 | { 56 | if(argc!=3) 57 | { 58 | printf("usage: %s destIP port\n",argv[0]); 59 | exit(1); 60 | } 61 | int len; 62 | struct in_addr server_addr; 63 | if(!inet_aton(argv[1], &server_addr)) 64 | perror("inet_aton"); 65 | struct sockaddr_in remote_addr; 66 | char buf[BUFSIZ]; 67 | memset(&remote_addr,0,sizeof(remote_addr)); 68 | remote_addr.sin_family=AF_INET; 69 | remote_addr.sin_addr=server_addr; 70 | int port=atoi(argv[2]); 71 | remote_addr.sin_port=htons(port); 72 | 73 | 74 | // for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define MAXREQ 256 13 | 14 | void* server(void* args) { 15 | int* consockfdAddr=(int *) args; 16 | int consockfd=*consockfdAddr; 17 | char reqbuf[MAXREQ]; 18 | int n; 19 | while (1) { 20 | memset(reqbuf,0, MAXREQ); 21 | n = read(consockfd,reqbuf,MAXREQ-1); /* Recv */ 22 | if (n <= 0) { 23 | perror("Error: read from socket"); 24 | close(consockfd); 25 | free(consockfdAddr); 26 | return NULL; 27 | } 28 | n = write(STDOUT_FILENO, reqbuf, strlen(reqbuf)); 29 | n = write(consockfd, reqbuf, strlen(reqbuf)); /* echo*/ 30 | if (n <= 0) { 31 | perror("Error: write to socket"); 32 | close(consockfd); 33 | free(consockfdAddr); 34 | return NULL; 35 | } 36 | } 37 | close(consockfd); 38 | free(consockfdAddr); 39 | return NULL; 40 | } 41 | 42 | 43 | int main(int argc, char *argv[]) 44 | { 45 | if(argc!=2) 46 | { 47 | printf("usage: %s port\n",argv[0]); 48 | return 1; 49 | } 50 | int port=atoi(argv[1]); 51 | 52 | struct sockaddr_in my_addr; 53 | my_addr.sin_family=AF_INET; 54 | my_addr.sin_addr.s_addr=INADDR_ANY; 55 | my_addr.sin_port=htons(port); 56 | 57 | int server_sockfd; 58 | if((server_sockfd=socket(AF_INET,SOCK_STREAM,0))<0) 59 | { 60 | perror("socket"); 61 | return 1; 62 | } 63 | 64 | int on=1; 65 | if((setsockopt(server_sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0) 66 | { 67 | perror("setsockopt failed"); 68 | return 1; 69 | } 70 | 71 | if (bind(server_sockfd,(struct sockaddr *)&my_addr,sizeof(my_addr))<0) 72 | { 73 | perror("bind"); 74 | return 1; 75 | } 76 | 77 | int sin_size=sizeof(struct sockaddr_in); 78 | struct sockaddr_in remote_addr; 79 | if(listen(server_sockfd,5)<0) 80 | { 81 | perror("listen"); 82 | return 1; 83 | } 84 | 85 | int inComeConnNum=0; 86 | while (1) { 87 | int *client_sockfd=malloc(sizeof(int)); 88 | if((*client_sockfd=accept(server_sockfd,(struct sockaddr *)&remote_addr,&sin_size))<0) 89 | { 90 | perror("Error: accept"); 91 | return 1; 92 | } 93 | inComeConnNum++; 94 | printf("[%d connections accepted] from client %s:%d\n",inComeConnNum,inet_ntoa(remote_addr.sin_addr),ntohs(remote_addr.sin_port)); 95 | 96 | server(client_sockfd); 97 | 98 | // pthread_t th; 99 | // if(pthread_create(&th, NULL, server, client_sockfd)!=0) 100 | // { 101 | // perror("pthread_create failed"); 102 | // exit(1); 103 | // } 104 | 105 | } 106 | close(server_sockfd); 107 | 108 | return 0; 109 | } -------------------------------------------------------------------------------- /CodeInSlides/chapter7/kv.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | "net/rpc" 8 | "sync" 9 | "flag" 10 | // "os" 11 | ) 12 | 13 | // 14 | // Common RPC request/reply definitions 15 | // 16 | 17 | const ( 18 | OK = "OK" 19 | ErrNoKey = "ErrNoKey" 20 | ) 21 | 22 | type Err string 23 | 24 | type PutArgs struct { 25 | Key string 26 | Value string 27 | } 28 | 29 | type PutReply struct { 30 | Err Err 31 | } 32 | 33 | type GetArgs struct { 34 | Key string 35 | } 36 | 37 | type GetReply struct { 38 | Err Err 39 | Value string 40 | } 41 | 42 | type DeleteArgs struct { 43 | Key string 44 | } 45 | 46 | type DeleteReply struct { 47 | Err Err 48 | } 49 | 50 | type ShowArgs struct { 51 | Type int 52 | } 53 | 54 | type ShowReply struct { 55 | Data map[string]string 56 | } 57 | 58 | // 59 | // Client 60 | // 61 | 62 | func connect(addr string) *rpc.Client { 63 | client, err := rpc.Dial("tcp", addr) 64 | if err != nil { 65 | log.Fatal("dialing:", err) 66 | } 67 | return client 68 | } 69 | 70 | func get(client *rpc.Client, key string) string { 71 | args := GetArgs{key} 72 | reply := GetReply{} 73 | err := client.Call("KV.Get", &args, &reply) 74 | if err != nil { 75 | log.Fatal("error:", err) 76 | } 77 | return reply.Value 78 | } 79 | 80 | func put(client *rpc.Client, key string, val string) { 81 | args := PutArgs{key, val} 82 | reply := PutReply{} 83 | err := client.Call("KV.Put", &args, &reply) 84 | if err != nil { 85 | log.Fatal("error:", err) 86 | } 87 | } 88 | 89 | func deleteKey(client *rpc.Client, key string) { 90 | args := DeleteArgs{key} 91 | reply := DeleteReply{} 92 | err := client.Call("KV.Delete", &args, &reply) 93 | if err != nil { 94 | log.Fatal("error:", err) 95 | } 96 | } 97 | 98 | func showAll(client *rpc.Client) map[string]string { 99 | args := ShowArgs{} 100 | reply := ShowReply{} 101 | err := client.Call("KV.Show", &args, &reply) 102 | if err != nil { 103 | log.Fatal("error:", err) 104 | } 105 | return reply.Data 106 | } 107 | 108 | func notifyExit(client *rpc.Client) { 109 | args := "" 110 | reply := "false" 111 | err := client.Call("KV.Exit", &args, &reply) 112 | if reply!="true" { 113 | fmt.Println("Server does not exit successfully! reply: ", reply) 114 | } 115 | if err != nil { 116 | log.Fatal("error:", err) 117 | } 118 | } 119 | 120 | func client(addr string) { 121 | client := connect(addr) 122 | var inOP, inKey, inValue string 123 | for { 124 | fmt.Printf("Input a KV operation (operation [key] [value]):\t") 125 | fmt.Scanln(&inOP, &inKey, &inValue) 126 | // fmt.Println(inOP, inKey, inValue) 127 | if inOP=="put" { 128 | put(client, inKey, inValue) 129 | fmt.Printf("put(%s, %s)\n", inKey, inValue) 130 | } else if inOP=="get" { 131 | value:=get(client, inKey) 132 | fmt.Printf("get(%s) -> %s\n", inKey, value) 133 | } else if inOP=="delete" { 134 | deleteKey(client, inKey) 135 | fmt.Printf("delete(%s)\n", inKey) 136 | } else if inOP=="show" { 137 | kvData:=showAll(client) 138 | fmt.Println("show KV: ", kvData) 139 | } else if inOP=="exit" { 140 | notifyExit(client); 141 | break 142 | } else { 143 | fmt.Println("Unknown operation ", inOP, inKey, inValue) 144 | } 145 | } 146 | client.Close() 147 | } 148 | 149 | // 150 | // Server 151 | // 152 | 153 | type KV struct { 154 | mu sync.Mutex 155 | data map[string]string 156 | } 157 | 158 | func server(addr string) { 159 | kv := new(KV) 160 | kv.data = map[string]string{} 161 | rpcs := rpc.NewServer() 162 | rpcs.Register(kv) 163 | l, e := net.Listen("tcp", addr) 164 | if e != nil { 165 | log.Fatal("listen error:", e) 166 | } 167 | for { 168 | conn, err := l.Accept() 169 | if err == nil { 170 | go rpcs.ServeConn(conn) 171 | } else { 172 | break 173 | } 174 | } 175 | l.Close() 176 | } 177 | 178 | func (kv *KV) Get(args *GetArgs, reply *GetReply) error { 179 | kv.mu.Lock() 180 | fmt.Printf("get(%s)\n", args.Key) 181 | defer kv.mu.Unlock() 182 | 183 | val, ok := kv.data[args.Key] 184 | if ok { 185 | reply.Err = OK 186 | reply.Value = val 187 | } else { 188 | reply.Err = ErrNoKey 189 | reply.Value = "" 190 | } 191 | return nil 192 | } 193 | 194 | func (kv *KV) Put(args *PutArgs, reply *PutReply) error { 195 | kv.mu.Lock() 196 | fmt.Printf("put(%s, %s)\n", args.Key, args.Value) 197 | defer kv.mu.Unlock() 198 | 199 | kv.data[args.Key] = args.Value 200 | reply.Err = OK 201 | return nil 202 | } 203 | 204 | func (kv *KV) Delete(args *DeleteArgs, reply *DeleteReply) error { 205 | kv.mu.Lock() 206 | fmt.Printf("delete(%s)\n", args.Key) 207 | defer kv.mu.Unlock() 208 | 209 | delete(kv.data, args.Key) 210 | reply.Err = OK 211 | return nil 212 | } 213 | 214 | func (kv *KV) Show(args *ShowArgs, reply *ShowReply) error { 215 | kv.mu.Lock() 216 | fmt.Println("show") 217 | defer kv.mu.Unlock() 218 | 219 | reply.Data = kv.data 220 | return nil 221 | } 222 | 223 | func (kv *KV) Exit(args *string, reply *string) error { 224 | kv.mu.Lock() 225 | fmt.Println("exit") 226 | defer kv.mu.Unlock() 227 | // defer os.Exit(0); 228 | 229 | *reply = "true" 230 | return nil 231 | } 232 | 233 | // 234 | // main 235 | // 236 | 237 | func main() { 238 | var mode string 239 | flag.StringVar(&mode, "mode", "", "client or server") 240 | var addr string 241 | flag.StringVar(&addr, "addr", "", "IP address and port (IP:port)") 242 | flag.Parse() 243 | 244 | if mode=="server" { 245 | fmt.Println("Listen to ", addr) 246 | } else if mode=="client" { 247 | fmt.Println("Connect to ", addr) 248 | } else { 249 | flag.Usage() 250 | return 251 | } 252 | fmt.Println("Working as ", mode) 253 | fmt.Printf("This is a simple KV store. Please play with fun ... \n\n") 254 | 255 | if mode=="server" { 256 | server(addr) 257 | } else if mode=="client" { 258 | client(addr) 259 | } 260 | 261 | fmt.Println("exit ...") 262 | } 263 | -------------------------------------------------------------------------------- /CodeInSlides/miscellaneous/MemLayout.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define bssSize (1024*1024) 8 | int stackSize=0; 9 | int heapSize=0; 10 | int mmapSize=0; 11 | 12 | static int array[bssSize]; 13 | 14 | int recursiveCalc(int n) 15 | { 16 | if(n==1) 17 | return n; 18 | else 19 | return recursiveCalc(n-1)+1; 20 | } 21 | 22 | int printMemMap(pid_t printPid) 23 | { 24 | printf("---------- mem layout begin ---------\n"); 25 | char *command[3]; 26 | command[0]=malloc(100*sizeof(char)); 27 | sprintf(command[0],"%s","pmap"); 28 | command[1]=malloc(100*sizeof(char)); 29 | sprintf(command[1],"%d",printPid); 30 | command[2]=NULL; 31 | pid_t pid = fork(); 32 | if (pid == -1) { //Error 33 | perror("Fork printMemMap ERROR: "); 34 | } 35 | else if (pid == 0) { //Child 36 | if(execvp(command[0], command)<0) 37 | perror("execvp(pmap) ERROR: "); 38 | } 39 | else { //Parent 40 | int childStatus; 41 | wait(&childStatus); 42 | } 43 | printf("---------- mem layout end ---------\n\n\n"); 44 | return 0; 45 | } 46 | 47 | int main() 48 | { 49 | printMemMap(getpid()); 50 | while(1) 51 | { 52 | printf("Please input stackSize: "); 53 | scanf("%d",&stackSize); 54 | printf("Call recursive calc in %d depth. Calc result: %d\n",stackSize,recursiveCalc(stackSize)); 55 | printMemMap(getpid()); 56 | 57 | printf("Please input heapSize size (B): "); 58 | scanf("%d",&heapSize); 59 | int allocatedSize=0; 60 | int *p; 61 | while(allocatedSize. 15 | 16 | CC = gcc 17 | CFLAGS = -pthread -march=native -O3 -mno-avx -D_XOPEN_SOURCE=600 -D_GNU_SOURCE -std=c99 \ 18 | -W -Wall -Werror 19 | LDFLAGS = -lrt -lpthread 20 | 21 | TARGETS = timectxsw timectxswws timesyscall timetctxsw timectxsw2 timetctxsw2 22 | 23 | all: bench 24 | 25 | bench: $(TARGETS) 26 | ./cpubench.sh 27 | 28 | clean: 29 | rm -f $(TARGETS) 30 | 31 | .PHONY: all bench 32 | -------------------------------------------------------------------------------- /CodeInSlides/miscellaneous/contextswitch/README: -------------------------------------------------------------------------------- 1 | Fork from https://github.com/tsuna/contextswitch 2 | Read https://blog.tsunanet.net/2010/11/how-long-does-it-take-to-make-context.html for more details 3 | 4 | Little micro-benchmarks to assess the performance overhead of context 5 | switching. 6 | 7 | timesyscall: Benchmarks the overhead of a system call. 8 | timectxsw: Benchmarks the overhead of context switching between 2 processes. 9 | timetctxsw: Benchmarks the overhead of context switching between 2 threads. 10 | timectxswws: Benchmarks the overhead of context switching between 2 processes 11 | using a working set of the size specified in argument. 12 | timetctxsw2: Benchmarks the overhead of context switching between 2 threads, 13 | by using a shed_yield() method. 14 | If you do taskset -a 1, all threads should be scheduled on the 15 | same processor, so you are really doing thread context switch. 16 | Then to be sure that you are really doing it, just do: 17 | strace -ff -tt -v taskset -a 1 ./timetctxsw2 18 | Now why sched_yield() is enough for testing ? Because, it place 19 | the current thread at the end of the ready queue. So the next 20 | ready thread will be scheduled. 21 | I also added sched_setscheduler(SCHED_FIFO) to get the best 22 | performances. 23 | -------------------------------------------------------------------------------- /CodeInSlides/miscellaneous/contextswitch/cpubench.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (C) 2010 Benoit Sigoure 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | fgrep 'model name' /proc/cpuinfo | sort -u | xargs 18 | pgrep vmware >/dev/null && echo Running under VMware 19 | ncpus=`sort -u /sys/devices/system/cpu/cpu*/topology/physical_package_id | wc -l` 20 | corepercpu=`sort -u /sys/devices/system/cpu/cpu*/topology/core_id | wc -l` 21 | threadpercore=`sed \ 22 | "s/2/10/g;\ 23 | s/3/11/g;\ 24 | s/4/100/g;\ 25 | s/5/101/g;\ 26 | s/6/110/g;\ 27 | s/7/111/g;\ 28 | s/8/1000/g;\ 29 | s/9/1001/g;\ 30 | s/a/1010/g;\ 31 | s/b/1011/g;\ 32 | s/c/1100/g;\ 33 | s/d/1101/g;\ 34 | s/e/1110/g;\ 35 | s/f/1111/g;\ 36 | s/[^1]//g" /sys/devices/system/cpu/cpu*/topology/thread_siblings \ 37 | | while read nthreads; do echo ${#nthreads}; done | sort -u` 38 | total=$((ncpus * corepercpu * threadpercore)) 39 | echo "$ncpus physical CPUs, $corepercpu cores/CPU,\ 40 | $threadpercore hardware threads/core = $total hw threads total" 41 | 42 | runbench() { 43 | $* ./timesyscall 44 | $* ./timectxsw 45 | $* ./timetctxsw 46 | $* ./timectxsw2 47 | $* ./timetctxsw2 48 | } 49 | 50 | echo '-- No CPU affinity --' 51 | runbench 52 | 53 | echo '-- With CPU affinity --' 54 | lastcpu=`awk . 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | static inline long long unsigned time_ns(struct timespec* const ts) { 29 | if (clock_gettime(CLOCK_REALTIME, ts)) { 30 | exit(1); 31 | } 32 | return ((long long unsigned) ts->tv_sec) * 1000000000LLU 33 | + (long long unsigned) ts->tv_nsec; 34 | } 35 | 36 | int main(void) { 37 | const int iterations = 500000; 38 | struct timespec ts; 39 | const int shm_id = shmget(IPC_PRIVATE, sizeof (int), IPC_CREAT | 0666); 40 | const pid_t other = fork(); 41 | int* futex = shmat(shm_id, NULL, 0); 42 | *futex = 0xA; 43 | if (other == 0) { 44 | for (int i = 0; i < iterations; i++) { 45 | sched_yield(); 46 | while (syscall(SYS_futex, futex, FUTEX_WAIT, 0xA, NULL, NULL, 42)) { 47 | // retry 48 | sched_yield(); 49 | } 50 | *futex = 0xB; 51 | while (!syscall(SYS_futex, futex, FUTEX_WAKE, 1, NULL, NULL, 42)) { 52 | // retry 53 | sched_yield(); 54 | } 55 | } 56 | return 0; 57 | } 58 | 59 | const long long unsigned start_ns = time_ns(&ts); 60 | for (int i = 0; i < iterations; i++) { 61 | *futex = 0xA; 62 | while (!syscall(SYS_futex, futex, FUTEX_WAKE, 1, NULL, NULL, 42)) { 63 | // retry 64 | sched_yield(); 65 | } 66 | sched_yield(); 67 | while (syscall(SYS_futex, futex, FUTEX_WAIT, 0xB, NULL, NULL, 42)) { 68 | // retry 69 | sched_yield(); 70 | } 71 | } 72 | const long long unsigned delta = time_ns(&ts) - start_ns; 73 | 74 | const int nswitches = iterations << 2; 75 | printf("%i process context switches in %lluns (%.1fns/ctxsw)\n", 76 | nswitches, delta, (delta / (float) nswitches)); 77 | wait(futex); 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /CodeInSlides/miscellaneous/contextswitch/timectxsw2.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2010 Benoit Sigoure 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | static inline long long unsigned time_ns(struct timespec* const ts) { 29 | if (clock_gettime(CLOCK_REALTIME, ts)) { 30 | exit(1); 31 | } 32 | return ((long long unsigned) ts->tv_sec) * 1000000000LLU 33 | + (long long unsigned) ts->tv_nsec; 34 | } 35 | 36 | int main(void) { 37 | const int iterations = 500000; 38 | struct timespec ts; 39 | const pid_t other = fork(); 40 | if (other == 0) { 41 | for (int i = 0; i < iterations; i++) 42 | sched_yield(); 43 | return 0; 44 | } 45 | 46 | const long long unsigned start_ns = time_ns(&ts); 47 | for (int i = 0; i < iterations; i++) 48 | sched_yield(); 49 | const long long unsigned delta = time_ns(&ts) - start_ns; 50 | 51 | const int nswitches = iterations << 2; 52 | printf("%i process context switches in %lluns (%.1fns/ctxsw) [Use sched_yield()]\n", 53 | nswitches, delta, (delta / (float) nswitches)); 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /CodeInSlides/miscellaneous/contextswitch/timectxswws.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2010 Benoit Sigoure 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | static inline long long unsigned time_ns(struct timespec* const ts) { 29 | if (clock_gettime(CLOCK_REALTIME, ts)) { 30 | exit(1); 31 | } 32 | return ((long long unsigned) ts->tv_sec) * 1000000000LLU 33 | + (long long unsigned) ts->tv_nsec; 34 | } 35 | 36 | static inline int get_iterations(int ws_pages) { 37 | int iterations = 1000; 38 | while (iterations * ws_pages * 4096L < 4294967296L) { // 4GB 39 | iterations += 1000; 40 | } 41 | return iterations; 42 | } 43 | 44 | int main(int argc, char** argv) { 45 | if (argc != 2) { 46 | fprintf(stderr, "usage: %s \n", *argv); 47 | return 1; 48 | } 49 | const long ws_pages = strtol(argv[1], NULL, 10); 50 | if (ws_pages < 0) { 51 | fprintf(stderr, "Invalid usage: working set size must be positive\n"); 52 | return 1; 53 | } 54 | const int iterations = get_iterations(ws_pages); 55 | struct timespec ts; 56 | 57 | long long unsigned memset_time = 0; 58 | if (ws_pages) { 59 | void* buf = malloc(ws_pages * 4096); 60 | memset_time = time_ns(&ts); 61 | for (int i = 0; i < iterations; i++) { 62 | memset(buf, i, ws_pages * 4096); 63 | } 64 | memset_time = time_ns(&ts) - memset_time; 65 | printf("%i memset on %4liK in %10lluns (%.1fns/page)\n", 66 | iterations, ws_pages * 4, memset_time, 67 | (memset_time / ((float) ws_pages * iterations))); 68 | free(buf); 69 | } 70 | 71 | const int shm_id = shmget(IPC_PRIVATE, (ws_pages + 1) * 4096, 72 | IPC_CREAT | 0666); 73 | const pid_t other = fork(); 74 | int* futex = shmat(shm_id, NULL, 0); 75 | void* ws = ((char *) futex) + 4096; 76 | *futex = 0xA; 77 | if (other == 0) { 78 | for (int i = 0; i < iterations; i++) { 79 | sched_yield(); 80 | while (syscall(SYS_futex, futex, FUTEX_WAIT, 0xA, NULL, NULL, 42)) { 81 | // retry 82 | sched_yield(); 83 | } 84 | *futex = 0xB; 85 | if (ws_pages) { 86 | memset(ws, i, ws_pages * 4096); 87 | } 88 | while (!syscall(SYS_futex, futex, FUTEX_WAKE, 1, NULL, NULL, 42)) { 89 | // retry 90 | sched_yield(); 91 | } 92 | } 93 | return 0; 94 | } 95 | 96 | const long long unsigned start_ns = time_ns(&ts); 97 | for (int i = 0; i < iterations; i++) { 98 | *futex = 0xA; 99 | if (ws_pages) { 100 | memset(ws, i, ws_pages * 4096); 101 | } 102 | while (!syscall(SYS_futex, futex, FUTEX_WAKE, 1, NULL, NULL, 42)) { 103 | // retry 104 | sched_yield(); 105 | } 106 | sched_yield(); 107 | while (syscall(SYS_futex, futex, FUTEX_WAIT, 0xB, NULL, NULL, 42)) { 108 | // retry 109 | sched_yield(); 110 | } 111 | } 112 | const long long unsigned delta = time_ns(&ts) - start_ns - memset_time * 2; 113 | 114 | const int nswitches = iterations * 4; 115 | printf("%i process context switches (wss:%4liK) in %12lluns (%.1fns/ctxsw)\n", 116 | nswitches, ws_pages * 4, delta, (delta / (float) nswitches)); 117 | wait(futex); 118 | return 0; 119 | } 120 | -------------------------------------------------------------------------------- /CodeInSlides/miscellaneous/contextswitch/timesyscall.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2010 Benoit Sigoure 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | static inline long long unsigned time_ns(struct timespec* const ts) { 23 | if (clock_gettime(CLOCK_REALTIME, ts)) { 24 | exit(1); 25 | } 26 | return ((long long unsigned) ts->tv_sec) * 1000000000LLU 27 | + (long long unsigned) ts->tv_nsec; 28 | } 29 | 30 | int main(void) { 31 | const int iterations = 10000000; 32 | struct timespec ts; 33 | const long long unsigned start_ns = time_ns(&ts); 34 | for (int i = 0; i < iterations; i++) { 35 | if (syscall(SYS_gettid) <= 1) { 36 | exit(2); 37 | } 38 | } 39 | const long long unsigned delta = time_ns(&ts) - start_ns; 40 | printf("%i system calls in %lluns (%.1fns/syscall)\n", 41 | iterations, delta, (delta / (float) iterations)); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /CodeInSlides/miscellaneous/contextswitch/timetctxsw.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2010 Benoit Sigoure 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | static inline long long unsigned time_ns(struct timespec* const ts) { 30 | if (clock_gettime(CLOCK_REALTIME, ts)) { 31 | exit(1); 32 | } 33 | return ((long long unsigned) ts->tv_sec) * 1000000000LLU 34 | + (long long unsigned) ts->tv_nsec; 35 | } 36 | 37 | static const int iterations = 500000; 38 | 39 | static void* thread(void* restrict ftx) { 40 | int* futex = (int*) ftx; 41 | for (int i = 0; i < iterations; i++) { 42 | sched_yield(); 43 | while (syscall(SYS_futex, futex, FUTEX_WAIT, 0xA, NULL, NULL, 42)) { 44 | // retry 45 | sched_yield(); 46 | } 47 | *futex = 0xB; 48 | while (!syscall(SYS_futex, futex, FUTEX_WAKE, 1, NULL, NULL, 42)) { 49 | // retry 50 | sched_yield(); 51 | } 52 | } 53 | return NULL; 54 | } 55 | 56 | int main(void) { 57 | struct timespec ts; 58 | const int shm_id = shmget(IPC_PRIVATE, sizeof (int), IPC_CREAT | 0666); 59 | int* futex = shmat(shm_id, NULL, 0); 60 | pthread_t thd; 61 | if (pthread_create(&thd, NULL, thread, futex)) { 62 | return 1; 63 | } 64 | *futex = 0xA; 65 | 66 | const long long unsigned start_ns = time_ns(&ts); 67 | for (int i = 0; i < iterations; i++) { 68 | *futex = 0xA; 69 | while (!syscall(SYS_futex, futex, FUTEX_WAKE, 1, NULL, NULL, 42)) { 70 | // retry 71 | sched_yield(); 72 | } 73 | sched_yield(); 74 | while (syscall(SYS_futex, futex, FUTEX_WAIT, 0xB, NULL, NULL, 42)) { 75 | // retry 76 | sched_yield(); 77 | } 78 | } 79 | const long long unsigned delta = time_ns(&ts) - start_ns; 80 | 81 | const int nswitches = iterations << 2; 82 | printf("%i thread context switches in %lluns (%.1fns/ctxsw)\n", 83 | nswitches, delta, (delta / (float) nswitches)); 84 | wait(futex); 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /CodeInSlides/miscellaneous/contextswitch/timetctxsw2.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2010 Benoit Sigoure 2 | // 3 | // This program is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program. If not, see . 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | static inline long long unsigned time_ns(struct timespec* const ts) { 26 | if (clock_gettime(CLOCK_REALTIME, ts)) { 27 | exit(1); 28 | } 29 | return ((long long unsigned) ts->tv_sec) * 1000000000LLU 30 | + (long long unsigned) ts->tv_nsec; 31 | } 32 | 33 | static const int iterations = 500000; 34 | 35 | static void* thread(void*ctx) { 36 | (void)ctx; 37 | for (int i = 0; i < iterations; i++) 38 | sched_yield(); 39 | return NULL; 40 | } 41 | 42 | int main(void) { 43 | struct sched_param param; 44 | param.sched_priority = 1; 45 | if (sched_setscheduler(getpid(), SCHED_FIFO, ¶m)) 46 | fprintf(stderr, "sched_setscheduler(): %s\n", strerror(errno)); 47 | 48 | struct timespec ts; 49 | pthread_t thd; 50 | if (pthread_create(&thd, NULL, thread, NULL)) { 51 | return 1; 52 | } 53 | 54 | long long unsigned start_ns = time_ns(&ts); 55 | for (int i = 0; i < iterations; i++) 56 | sched_yield(); 57 | long long unsigned delta = time_ns(&ts) - start_ns; 58 | 59 | const int nswitches = iterations << 2; 60 | printf("%i thread context switches in %lluns (%.1fns/ctxsw) [Use sched_yield()]\n", 61 | nswitches, delta, (delta / (float) nswitches)); 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /CodeInSlides/miscellaneous/multipipe-popen/multipipe-popen.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2009-2010 Bart Trojanowski 3 | * Licensed under GPLv2, or later, at your choosing. 4 | * 5 | * bidirectional popen() call 6 | * 7 | * @param rwepipe - int array of size three 8 | * @param exe - program to run 9 | * @param argv - argument list 10 | * @return pid or -1 on error 11 | * 12 | * The caller passes in an array of three integers (rwepipe), on successful 13 | * execution it can then write to element 0 (stdin of exe), and read from 14 | * element 1 (stdout) and 2 (stderr). 15 | */ 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | int popenRWE(int *rwepipe, char *command) { 25 | int in[2]; 26 | int out[2]; 27 | int err[2]; 28 | int pid; 29 | int rc; 30 | 31 | rc = pipe(in); 32 | if (rc<0) 33 | goto error_in; 34 | 35 | rc = pipe(out); 36 | if (rc<0) 37 | goto error_out; 38 | 39 | rc = pipe(err); 40 | if (rc<0) 41 | goto error_err; 42 | 43 | pid = fork(); 44 | if (pid > 0) { /* parent */ 45 | close(in[0]); 46 | close(out[1]); 47 | close(err[1]); 48 | rwepipe[0] = in[1]; 49 | rwepipe[1] = out[0]; 50 | rwepipe[2] = err[0]; 51 | return pid; 52 | } else if (pid == 0) { /* child */ 53 | close(in[1]); 54 | close(out[0]); 55 | close(err[0]); 56 | close(0); 57 | if(!dup(in[0])) { 58 | ; 59 | } 60 | close(1); 61 | if(!dup(out[1])) { 62 | ; 63 | } 64 | close(2); 65 | if(!dup(err[1])) { 66 | ; 67 | } 68 | 69 | execl( "/bin/sh", "sh", "-c", command, NULL ); 70 | _exit(1); 71 | } else 72 | goto error_fork; 73 | 74 | return pid; 75 | 76 | error_fork: 77 | close(err[0]); 78 | close(err[1]); 79 | error_err: 80 | close(out[0]); 81 | close(out[1]); 82 | error_out: 83 | close(in[0]); 84 | close(in[1]); 85 | error_in: 86 | return -1; 87 | } 88 | 89 | int pcloseRWE(int pid, int *rwepipe) 90 | { 91 | int status; 92 | close(rwepipe[0]); 93 | close(rwepipe[1]); 94 | close(rwepipe[2]); 95 | waitpid(pid, &status, 0); 96 | return status; 97 | } 98 | 99 | void* ReadOutput(void* args) { 100 | int* read_fd = (int*) args; 101 | char bufferRead[BUFSIZ]; 102 | int totalOutputBytes=0; 103 | memset(bufferRead,0,sizeof(bufferRead[0])*(BUFSIZ)); 104 | int oByte=0; 105 | while((oByte=read(*read_fd,bufferRead,BUFSIZ))>0) 106 | { 107 | totalOutputBytes=totalOutputBytes+oByte; 108 | printf("%s",bufferRead); 109 | memset(bufferRead,0,sizeof(bufferRead[0])*(BUFSIZ)); 110 | usleep(100000);//检测输出的间隔 111 | } 112 | printf("\n\nRead done!\n\n"); 113 | } 114 | 115 | int main() 116 | { 117 | int fd[3]; 118 | int pid=0; 119 | pid=popenRWE(fd,"./testProgram"); 120 | if(pid<0) 121 | { 122 | fprintf(stderr, "popenRWE ERROR!\n"); 123 | exit(1); 124 | } 125 | int write_fd=fd[0]; 126 | int read_fd=fd[1]; 127 | 128 | printf("write_fd %d, read_fd %d\n",write_fd,read_fd); 129 | 130 | pthread_t th; 131 | if(pthread_create(&th, NULL, ReadOutput, &read_fd)!=0) 132 | { 133 | perror("pthread_create failed"); 134 | exit(1); 135 | } 136 | 137 | char bufferWrite[BUFSIZ]; 138 | int totalInputBytes=0; 139 | while(1) 140 | { 141 | memset(bufferWrite,0,sizeof(bufferWrite[0])*(BUFSIZ)); 142 | sprintf(bufferWrite,"test input %d\n",totalInputBytes); 143 | int byteToWrite=strlen(bufferWrite); 144 | int byteWritten=0; 145 | while(byteWritten=1000) 159 | { 160 | close(write_fd); //关闭用户程序的stdin,相当于主动给用户程序发一个EOF,促使他结束(如果同学没写好没处理EOF,他可能会崩) 161 | break; 162 | } 163 | usleep(100000);//给输入的间隔 164 | } 165 | pthread_join(th, NULL); 166 | pcloseRWE(pid,fd); 167 | } 168 | -------------------------------------------------------------------------------- /CodeInSlides/miscellaneous/multipipe-popen/testProgram.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | char buff[1024]={0}; 7 | int totalLine=0; 8 | while(fgets(buff, 1024, stdin)!=NULL) 9 | { 10 | fprintf(stdout, "Line %d: %s", totalLine, buff); 11 | fflush(stdout); //如果用户程序没有主动flush,程序没结束的话外面可能永远看不到他的输出,测量出来的时间也很长 12 | //但没关系,这个时间是用户程序没写好导致的,算到他头上也不亏 13 | totalLine++; 14 | memset(buff,0,sizeof(buff[0])*1024); 15 | } 16 | } --------------------------------------------------------------------------------