0
点赞
收藏
分享

微信扫一扫

一起来写web server 04 -- 线程池版本

IT程序员 2021-09-27 阅读 47

从这个版本开始,后面的代码差不多是越来越难啦.

这个版本,我们主要是要实现一个线程池版本的web server.这个版本的设计出自UNP.

思想

思想非常简单,那就是父线程首先构建n多子线程,这些子线程全部争抢全局的一把锁,只有抢到了锁的线程才能够调用accept函数,否则都会阻塞掉.

代码

/*- 
* 线程池版本的web server.主要的思想是事先构建一个线程池,只是需要注意的是,accept的时候需要加锁.
*/

int listenfd; /* 全局的一个监听套接字 */
MutexLock mutex; /* 全局的一把锁 */

int main(int argc, char *argv[])
{
    listenfd = Open_listenfd(8080); /* 8080号端口监听 */
    //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); /* 关闭连接 */
    }
}

一般涉及到多线程的资源共享,锁或者说互斥,加上一个同步机制,总是逃不开的话题.
对于共享资源的写,总是要加锁的.如何来构造一把锁呢?我这里的代码参考了muduo库的设计.

我们一起来看一下MutexLock这个类.

class MutexLock : noncopyable
{
    private:
        pthread_mutex_t mutex_; /* 这是系统定义的锁的类型 */
        pid_t holder_; /* 记录拥有线程的id */
     ...
}

它的构造函数,仅仅是调用普通的锁的初始化的代码:

MutexLock()
        : holder_(0)
    {
        pthread_mutex_init(&mutex_, NULL); /* 初始化 */
    }

它的析构函数,主要是调用锁的销毁函数.

~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库设计了另外一个类,叫做MutexLockGuard.这个类非常简单:

class MutexLockGuard : noncopyable
{
public:
    explicit MutexLockGuard(MutexLock& mutex)
        : mutex_(mutex)
    {
        mutex_.lock(); /* 构造时加锁 */
    }
    ~MutexLockGuard()
    {
        mutex_.unlock(); /* 析构时解锁 */
    }
private:
    MutexLock& mutex_; /* 持有锁的一个引用 */
};

通过这个类,我们就可以很方便的实现加锁和解锁操作了,我们只需要向之前代码里那样使用就行了:

{
    MutexLockGuard lock(mutex); /* 加锁 */
    ...do other thing...
}

在这个中括号包围的作用域里,锁是有效的,出了这个作用域,lock析构了,锁就解开了,代码很漂亮.

总结

好了,这个版本的代码就是这样啦,感兴趣的同学可以到这里来查看代码:
https://github.com/lishuhuakai/Spweb

举报

相关推荐

0 条评论