從這個版本開始,后面的代碼差不多是越來越難啦.
這個版本,我們主要是要實現(xiàn)一個線程池版本的web server
.這個版本的設(shè)計出自UNP
.
思想
思想非常簡單,那就是父線程首先構(gòu)建n
多子線程,這些子線程全部爭搶全局的一把鎖,只有搶到了鎖的線程才能夠調(diào)用accept
函數(shù),否則都會阻塞掉.
代碼
/*-
* 線程池版本的web server.主要的思想是事先構(gòu)建一個線程池,只是需要注意的是,accept的時候需要加鎖.
*/
int listenfd; /* 全局的一個監(jiān)聽套接字 */
MutexLock mutex; /* 全局的一把鎖 */
int main(int argc, char *argv[])
{
listenfd = Open_listenfd(8080); /* 8080號端口監(jiān)聽 */
//signal(SIGPIPE, SIG_IGN);
pthread_t tids[10];
void* thread_main(void *);
for (int i = 0; i < 10; ++i) {
int *arg = (int *)Malloc(sizeof(int)); /* 這個東西不會共享 */
*arg = i;
Pthread_create(&tids[i], NULL, thread_main, (void *)arg);
}
for ( ; ; )
pause();
return 0;
}
void* thread_main(void *arg)
{
printf("thread %d starting\n", *(int*)arg);
Free(arg);
struct sockaddr cliaddr;
socklen_t clilen;
int connfd;
while (true) {
{
MutexLockGuard lock(mutex); /* 加鎖 */
connfd = Accept(listenfd, &cliaddr, &clilen);
}
doit(connfd); /* 處理連接 */
close(connfd); /* 關(guān)閉連接 */
}
}
鎖
一般涉及到多線程的資源共享,鎖或者說互斥,加上一個同步機制,總是逃不開的話題.
對于共享資源的寫,總是要加鎖的.如何來構(gòu)造一把鎖呢?我這里的代碼參考了muduo
庫的設(shè)計.
我們一起來看一下MutexLock
這個類.
class MutexLock : noncopyable
{
private:
pthread_mutex_t mutex_; /* 這是系統(tǒng)定義的鎖的類型 */
pid_t holder_; /* 記錄擁有線程的id */
...
}
它的構(gòu)造函數(shù),僅僅是調(diào)用普通的鎖的初始化的代碼:
MutexLock()
: holder_(0)
{
pthread_mutex_init(&mutex_, NULL); /* 初始化 */
}
它的析構(gòu)函數(shù),主要是調(diào)用鎖的銷毀函數(shù).
~MutexLock()
{
assert(holder_ == 0);
pthread_mutex_destroy(&mutex_); /* 銷毀鎖 */
}
MutexLock
這個類巧妙的利用了CPP
類的特性來管理鎖這個資源.
接下來比較重要的是加鎖以及解鎖操作:
void lock()
{
MCHECK(pthread_mutex_lock(&mutex_));
assignHolder(); /* 指定擁有者 */
}
void unlock()
{
unassignHolder(); /* 丟棄擁有者 */
MCHECK(pthread_mutex_unlock(&mutex_));
}
如何來使用這個鎖呢?muduo
庫設(shè)計了另外一個類,叫做MutexLockGuard
.這個類非常簡單:
class MutexLockGuard : noncopyable
{
public:
explicit MutexLockGuard(MutexLock& mutex)
: mutex_(mutex)
{
mutex_.lock(); /* 構(gòu)造時加鎖 */
}
~MutexLockGuard()
{
mutex_.unlock(); /* 析構(gòu)時解鎖 */
}
private:
MutexLock& mutex_; /* 持有鎖的一個引用 */
};
通過這個類,我們就可以很方便的實現(xiàn)加鎖和解鎖操作了,我們只需要向之前代碼里那樣使用就行了:
{
MutexLockGuard lock(mutex); /* 加鎖 */
...do other thing...
}
在這個中括號包圍的作用域里,鎖是有效的,出了這個作用域,lock
析構(gòu)了,鎖就解開了,代碼很漂亮.
總結(jié)
好了,這個版本的代碼就是這樣啦,感興趣的同學(xué)可以到這里來查看代碼:
https://github.com/lishuhuakai/Spweb