《CSAPP》(第3版)答案(第十二章)(一)
P16
#include <stdio.h>
#include "csapp.h"
void *thread(void *vargp);
#define DEFAULT 4
int main(int argc, char* argv[]) {
int N;
if (argc > 2)
unix_error("too many param");
else if (argc == 2)
N = atoi(argv[1]);
else
N = DEFAULT;
int i;
pthread_t tid;
for (i = 0; i < N; i++) {
Pthread_create(&tid, NULL, thread, NULL);
}
Pthread_exit(NULL);
}
void *thread(void *vargp) {
printf("Hello, world\n");
return NULL;
}
P17
- A
主线程没有等待另一个线程。 - B
#include "csapp.h"
void *thread(void *vargp);
int main()
{
pthread_t tid;
Pthread_create(&tid, NULL, thread, NULL);
// exit(0);
Pthread_exit(NULL);
}
/* Thread routine */
void *thread(void *vargp)
{
Sleep(1);
printf("Hello, world!\n");
return NULL;
}
P18
- A
不安全 - B
安全 - C
不安全
P19
#include <stdio.h>
#include "csapp.h"
#define WRITE_LIMIT 100000
#define PEOPLE 4
static int readtimes;
static int writetimes;
static int readcnt;
// if a reader is waiting when writing, reader first next round
static int reader_first;
sem_t mutex, w;
void *reader(void *vargp) {
while (1) {
P(&mutex);
readcnt++;
if (readcnt == 1)
P(&w);
V(&mutex);
/* Critical section */
readtimes++;
reader_first = 0;
/* Critical section */
P(&mutex);
readcnt--;
if (readcnt == 0)
V(&w);
V(&mutex);
}
}
void *writer(void *vargp) {
while (1) {
if (reader_first == 1)
continue;
P(&w);
/* Critical section */
writetimes++;
if (writetimes == WRITE_LIMIT) {
printf("read/write: %d/%d\n", readtimes, writetimes);
exit(0);
}
/* Critical section */
// if a reader is waiting, reader first next round
if (readcnt == 1)
reader_first = 1;
V(&w);
}
}
void init(void) {
readcnt = 0;
readtimes = 0;
writetimes = 0;
reader_first = 0;
Sem_init(&w, 0, 1);
Sem_init(&mutex, 0, 1);
}
int main(int argc, char* argv[]) {
int i;
pthread_t tid;
init();
for (i = 0; i < PEOPLE; i++)
if (i%2 == 0)
Pthread_create(&tid, NULL, reader, NULL);
else
Pthread_create(&tid, NULL, writer, NULL);
Pthread_exit(NULL);
exit(0);
}
P20
#include <stdio.h>
#include "csapp.h"
#define WRITE_LIMIT 100000
#define PEOPLE 20 // 10 reader and 10 writer
#define N 5
static int readtimes;
static int writetimes;
sem_t mutex;
sem_t readercnt;
void *reader(void *vargp) {
while (1) {
P(&readercnt);
P(&mutex);
readtimes++;
V(&mutex);
V(&readercnt);
}
}
void *writer(void *vargp) {
while (1) {
P(&mutex);
writetimes++;
if (writetimes == WRITE_LIMIT) {
printf("read/write: %d/%d\n", readtimes, writetimes);
exit(0);
}
V(&mutex);
}
}
void init(void) {
readtimes = 0;
writetimes = 0;
Sem_init(&mutex, 0, 1);
Sem_init(&readercnt, 0, N);
}
int main(int argc, char* argv[]) {
int i;
pthread_t tid;
init();
for (i = 0; i < PEOPLE; i++) {
if (i%2 == 0)
Pthread_create(&tid, NULL, reader, NULL);
else
Pthread_create(&tid, NULL, writer, NULL);
}
Pthread_exit(NULL);
exit(0);
}
P21
#include <stdio.h>
#include "csapp.h"
#define WRITE_LIMIT 100000
#define PEOPLE 4
static int readtimes;
static int writetimes;
static int writecnt;
sem_t mutex, w;
static int number;
void *reader(void *vargp) {
while (1) {
// writer first
if (writecnt > 0)
continue;
P(&w);
/* Critical section */
readtimes++;
/* Critical section */
V(&w);
}
}
void *writer(void *vargp) {
while (1) {
P(&mutex);
// one more writer wait to write
writecnt++;
V(&mutex);
P(&w);
/* Critical section */
writetimes++;
if (writetimes == WRITE_LIMIT) {
printf("read/write: %d/%d\n", readtimes, writetimes);
exit(0);
}
/* Critical section */
V(&w);
P(&mutex);
// writer has written
writecnt--;
V(&mutex);
}
}
void init(void) {
writecnt = 0;
readtimes = 0;
writetimes = 0;
Sem_init(&w, 0, 1);
Sem_init(&mutex, 0, 1);
}
int main(int argc, char* argv[]) {
int i;
pthread_t tid;
init();
for (i = 0; i < PEOPLE; i++) {
if (i%2 == 0)
Pthread_create(&tid, NULL, reader, NULL);
else
Pthread_create(&tid, NULL, writer, NULL);
}
Pthread_exit(NULL);
exit(0);
}
P22
#include "csapp.h"
/* read line from connfd and echo line to connfd */
int echo_line(int connfd);
void command(void);
int main(int argc, char **argv)
{
int listenfd, connfd;
socklen_t clientlen;
struct sockaddr_storage clientaddr;
fd_set read_set, ready_set;
if (argc != 2) {
fprintf(stderr, "usage: %s <port>\nuse port 5000 here\n", argv[0]);
// default port 5000
listenfd = Open_listenfd("5000");
} else {
listenfd = Open_listenfd(argv[1]); //line:conc:select:openlistenfd
}
FD_ZERO(&read_set); /* Clear read set */ //line:conc:select:clearreadset
FD_SET(STDIN_FILENO, &read_set); /* Add stdin to read set */ //line:conc:select:addstdin
FD_SET(listenfd, &read_set); /* Add listenfd to read set */ //line:conc:select:addlistenfd
// max n for select
int n = listenfd+1;
while (1) {
ready_set = read_set;
Select(n, &ready_set, NULL, NULL, NULL); //line:conc:select:select
if (FD_ISSET(STDIN_FILENO, &ready_set)) //line:conc:select:stdinready
command(); /* Read command line from stdin */
if (FD_ISSET(listenfd, &ready_set)) { //line:conc:select:listenfdready
clientlen = sizeof(struct sockaddr_storage);
connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
// listen to accepted io ports
if (connfd+1 > FD_SETSIZE) {
fprintf(stderr, "too many clients\n");
Close(connfd);
}
n = n > connfd+1 ? n : connfd+1;
FD_SET(connfd, &read_set);
}
// echo one line every time
int fd;
for (fd = listenfd+1; fd < n; fd++)
if (FD_ISSET(fd, &ready_set))
if (echo_line(fd) == -1) {
Close(fd);
FD_CLR(fd, &read_set);
}
}
}
void command(void) {
char buf[MAXLINE];
if (!Fgets(buf, MAXLINE, stdin))
exit(0); /* EOF */
printf("%s", buf); /* Process the input command */
}
int echo_line(int connfd) {
ssize_t n;
char buf[1];
while ((n = Rio_readn(connfd, buf, 1)) > 0) {
Rio_writen(connfd, buf, n);
if (buf[0] = '\n')
return 0;
}
return -1;
}
P23
@@ -1,7 +1,5 @@
/*
- * 12.23.bug.c - A concurrent echo server based on select
- *
- * bug in this file
+ * 12.23.c - A concurrent echo server based on select
*/
#include "csapp.h"
@@ -105,15 +103,21 @@
/* If the descriptor is ready, echo a text line from it */
if ((connfd > 0) && (FD_ISSET(connfd, &p->ready_set))) {
p->nready--;
- if ((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) {
+ if ((n = rio_readlineb(&rio, buf, MAXLINE)) > 0) {
byte_cnt += n; //line:conc:echoservers:beginecho
printf("Server received %d (%d total) bytes on fd %d\n",
n, byte_cnt, connfd);
Rio_writen(connfd, buf, n); //line:conc:echoservers:endecho
}
-
/* EOF detected, remove descriptor from pool */
+ else if (n == 0) {
+ Close(connfd); //line:conc:echoservers:closeconnfd
+ FD_CLR(connfd, &p->read_set); //line:conc:echoservers:beginremove
+ p->clientfd[i] = -1; //line:conc:echoservers:endremove
+ }
+ /* n == -1, it's an error */
else {
+ fprintf(stderr, "error in fd %d, close fd %d connection\n", connfd, connfd);
Close(connfd); //line:conc:echoservers:closeconnfd
FD_CLR(connfd, &p->read_set); //line:conc:echoservers:beginremove
p->clientfd[i] = -1; //line:conc:echoservers:endremove
P24
是
P25
thread safe?
Yes, mutex make it safe
reentrant? (我也不知道reentrant咋翻译)
No, share the same mutex
P26
#include <stdio.h>
#include "csapp.h"
/*
* struct hostent *gethostbyname(const char *name)
*
* struct hostent {
* char *h_name;
* char **h_aliases;
* int h_addrtype;
* int h_length;
* char **h_addr_list;
* }
*/
static sem_t mutex;
static void init_mutex(void) {
Sem_init(&mutex, 0, 1);
}
struct hostent *gethostbyname_ts(const char *name, struct hostent *host) {
struct hostent *sharehost;
P(&mutex);
sharehost = gethostbyname(name);
// copy int
host->h_addrtype = sharehost->h_addrtype;
host->h_length = sharehost->h_length;
// copy char *
host->h_name = (char*)Malloc(strlen(sharehost->h_name));
strcpy(host->h_name, sharehost->h_name);
// copy char **
int i;
for (i = 0; sharehost->h_aliases[i] != NULL; i++) {}
host->h_aliases = (char**)Malloc(sizeof(char*) * (i+1));
for (i = 0; sharehost->h_aliases[i] != NULL; i++) {
// copy every char *
host->h_aliases[i] = (char*)Malloc(strlen(sharehost->h_aliases[i]));
strcpy(host->h_aliases[i], sharehost->h_aliases[i]);
}
host->h_aliases[i] = NULL;
for (i = 0; sharehost->h_addr_list[i] != NULL; i++) {}
host->h_addr_list = (char**)Malloc(sizeof(char*) * (i+1));
for (i = 0; sharehost->h_addr_list[i] != NULL; i++) {
// copy every char *
host->h_addr_list[i] = (char*)Malloc(strlen(sharehost->h_addr_list[i]));
strcpy(host->h_addr_list[i], sharehost->h_addr_list[i]);
}
host->h_addr_list[i] = NULL;
V(&mutex);
return host;
}
int main(int argc, char* argv[]) {
init_mutex();
struct hostent host;
gethostbyname_ts("127.0.0.1", &host);
// result in &host
return 0;
}
P27
I cannot explain.