Skip to content

Commit

Permalink
Pre-create threads for serving the clients.
Browse files Browse the repository at this point in the history
  • Loading branch information
pvc1989 committed Aug 31, 2024
1 parent 6923dc7 commit 4ed1ec8
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 12 deletions.
4 changes: 3 additions & 1 deletion programming/csapp/labs/proxy.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,12 @@ void serve_by_thread(int client_fd) {
}
```
## 2.2 Precreated threads (TODO)
## 2.2 Precreated threads
A more efficient but complicated version like [`echoservert-pre.c`](../12_concurrent_programming.md#echoservert-pre) in the textbook is also possible.
The binary `sem_t` for protecting the pool could be replaced by a `pthread_mutex_t`, which is used in my solution.
# 3. Caching web objects
## 3.1 LRU based on [`uthash`](http://troydhanson.github.io/uthash/userguide.html) and [`utlist`](troydhanson.github.io/uthash/utlist.html)
Expand Down
2 changes: 1 addition & 1 deletion programming/csapp/labs/proxy/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ all: proxy lru_test lru_test_cpp
lru_test: lru_test.o lru.o csapp.o
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)

proxy: proxy.o csapp.o lru.o
proxy: proxy.o csapp.o lru.o pool.o
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)

$(CXXOBJS) : %.cpp.o : %.cpp
Expand Down
4 changes: 3 additions & 1 deletion programming/csapp/labs/proxy/pool.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@ struct _pool {
};

/* Create an empty, bounded, shared FIFO buffer with n slots */
void pool_init(pool_t *p, int n) {
pool_t *pool_init(int n) {
pool_t *p = Malloc(sizeof(pool_t));
p->buf = Calloc(n, sizeof(int));
p->n = n; /* Buffer holds max of n items */
p->front = p->rear = 0; /* Empty buffer iff front == rear */
_mutex = &p->queue;
pthread_once(&once, mutex_init);
Sem_init(&p->slots, 0, n); /* Initially, buf has n empty slots */
Sem_init(&p->items, 0, 0); /* Initially, buf has zero data items */
return p;
}

/* Clean up buffer p */
Expand Down
2 changes: 1 addition & 1 deletion programming/csapp/labs/proxy/pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
struct _pool;
typedef struct _pool pool_t;

void pool_init(pool_t *p, int n);
pool_t *pool_init(int n);
void pool_deinit(pool_t *p);
void pool_insert(pool_t *p, int item);
int pool_remove(pool_t *p);
Expand Down
48 changes: 40 additions & 8 deletions programming/csapp/labs/proxy/proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "csapp.h"
#include "lru.h" // the LRU cache
#include "pool.h" // the FD pool

/* Recommended max cache and object sizes */
#define MAX_CACHE_SIZE 1049000
Expand All @@ -13,9 +14,11 @@ static lru_t *lru = NULL;
/* You won't lose style points for including this long line in your code */
static const char *user_agent_hdr = "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.3) Gecko/20120305 Firefox/10.0.3\r\n";

#define CONCURRENT
// #define CONCURRENT_BY_ONCEONLY_THREAD
#define CONCURRENT_BY_REUSABLE_THREAD

#ifndef CONCURRENT
#if !defined(CONCURRENT_BY_ONCEONLY_THREAD) && \
!defined(CONCURRENT_BY_REUSABLE_THREAD)
#define PRINTF(...) (printf(__VA_ARGS__))
#define LRU_PRINT(...) (lru_print(__VA_ARGS__))
#define PTHREAD_PRINTF(...) (printf(__VA_ARGS__))
Expand Down Expand Up @@ -276,24 +279,44 @@ void serve(int client_fd) {
Close(client_fd);
}

#ifdef CONCURRENT_BY_ONCEONLY_THREAD
/**
* @brief The routine run in a thread.
* @brief The routine run in a once-only thread.
*/
void *routine(void *vargp) {
void *routine_in_onceonly_thread(void *vargp) {
int client_fd = *((int *)vargp);
Pthread_detach(Pthread_self());
Free(vargp);
serve(client_fd);
return NULL;
}

void serve_by_thread(int client_fd) {
void serve_by_onceonly_thread(int client_fd) {
int *client_fd_ptr = Malloc(sizeof(int));
*client_fd_ptr = client_fd;

pthread_t tid;
Pthread_create(&tid, NULL, routine, client_fd_ptr);
Pthread_create(&tid, NULL, routine_in_onceonly_thread, client_fd_ptr);
}
#endif // CONCURRENT_BY_ONCEONLY_THREAD

#ifdef CONCURRENT_BY_REUSABLE_THREAD
#define NTHREADS 4
#define POOLSIZE 16
static pool_t *pool; /* Shared buffer of connected descriptors */

/**
* @brief The routine run in a reusable thread.
*/
void *routine_in_reusable_thread(void *vargp) {
Pthread_detach(Pthread_self());
while (1) {
int connect_fd = pool_remove(pool);
serve(connect_fd);
}
return NULL;
}
#endif // CONCURRENT_BY_REUSABLE_THREAD

int main(int argc, char **argv)
{
Expand All @@ -306,15 +329,24 @@ int main(int argc, char **argv)
exit(0);
}

#ifdef CONCURRENT_BY_REUSABLE_THREAD
pool = pool_init(POOLSIZE);
pthread_t tid;
for (int i = 0; i < NTHREADS; i++)
Pthread_create(&tid, NULL, routine_in_reusable_thread, NULL);
#endif // CONCURRENT_BY_REUSABLE_THREAD

lru = lru_construct(MAX_CACHE_SIZE);
int listen_fd = Open_listenfd(argv[1]);
while (1) {
int client_fd = Accept(listen_fd, (SA *)&client_addr, &client_len);
Getnameinfo((SA *) &client_addr, client_len,
client_host, MAXLINE, client_port, MAXLINE, 0);
PTHREAD_PRINTF("Connected to client %s:%s\n", client_host, client_port);
#ifdef CONCURRENT
serve_by_thread(client_fd);
#ifdef CONCURRENT_BY_ONCEONLY_THREAD
serve_by_onceonly_thread(client_fd);
#elif defined(CONCURRENT_BY_REUSABLE_THREAD)
pool_insert(pool, client_fd);
#else
serve(client_fd);
#endif
Expand Down

0 comments on commit 4ed1ec8

Please sign in to comment.