linux下的c++ 多線程封裝

最近爲了學習linux 下的多線程,自己用c++封裝了一個簡易的局域網多線程聊天服務器,期間遇到了一些坑寫到這裏與大家共勉!
主要功能: 封裝了一個名叫pthread_serv的類對每一個客戶端的響應建立一個進程進行信息轉發。
遇到的問題: 在使用linux提供的線程創建函數

int pthread_create(pthread_t *tidp,const pthread_attr_t *attr,
(void*)(*start_rtn)(void*),void *arg) 

時因爲線程主函數start_rt函數是pthread_serv類中的普通函數,在調用的時候c++ 會隱式的傳入this指針,這樣start_rtn就有了兩個參數,但linux提供的pthread_create函數中start_rtn只能有一個(void*) 參數,這是個很嚴重的問題,我們編譯都過不去…..
針對該問題的解決方法: 很明顯,我們必須幹掉start_rtn中這個可惡的this指針。現在有兩個辦法可以做到這點:
1. 將start_rtn聲明爲該類的友元函數
2. 將start_rtn聲明爲靜態函數
我用了第二種方法,將start_rtn聲明爲靜態函數,這樣再調用

int pthread_create(pthread_t *tidp,const pthread_attr_t *attr,
(void*)(*start_rtn)(void*),void *arg)

就沒有問題了,不過舊問題去了,新問題又來了!!! 想哭…。c++ 中靜態函數中只能調用靜態成員,靜態函數。所以start_rtn函數不能調用類裏面的變量&&函數了,我也不能將所有的變量,函數都聲明成靜態的吧。所以我的解決方法是將this指針當做start_rtn的參數。

 pthread_create(&id_t,NULL,hander_clnt,this);

再在start_rtn中將參數類型轉化成一個對象指針,用這個對象指針調用一個普通的函數,這個普通的函數就作爲線程主函數使用。

void* pthread_serv::hander_clnt(void *msg)
 {
     pthread_serv *serv = static_cast<pthread_serv*>(msg);
     serv->run_clnt(); //run_clnt()就作爲線程主函數用
 }

下面是我的代碼,比較搓,求輕拍..(逃~~)

#ifndef PTHREAD_SERV_H
#define PTHREAD_SERV_H
#include <iostream>
#include <algorithm>
#include <list>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h> //sockaddr_in
#include <pthread.h>
#include <unistd.h>
#include <sys/socket.h>
class pthread_serv
{
public:
    explicit pthread_serv();
    inline void error_hander(char *msg);
    static void *hander_clnt(void *msg);
    void send_msg(char *msg,int len);
    void run();
    void run_clnt();
    pthread_t id_t;
private:
    pthread_mutex_t mutex;
    int serv_sock;
    int clnt_sock;
    sockaddr_in serv_addr;
    sockaddr_in clnt_addr;
    std::list<int> clnt_sock_list;
};

#endif // PTHREAD_SERV_H
#include "pthread_serv.h"
pthread_serv::pthread_serv()
{
    serv_sock = socket(PF_INET,SOCK_STREAM,0);
    memset(&serv_addr,0,sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(8888);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(serv_sock,(sockaddr*)&serv_addr,sizeof(serv_addr)) == -1)
        error_hander("bind() error!");
    if(listen(serv_sock,100) == -1)
        error_hander("listen() error!");
}
 inline void pthread_serv::error_hander(char *msg)
 {
     fputs(msg,stdout);
 }

 void pthread_serv::send_msg(char *msg,int len)
 {
     std::list<int>::iterator it;
     pthread_mutex_lock(&mutex);
   for(it=clnt_sock_list.begin(); it!=clnt_sock_list.end(); it++)
         write(*it,msg,len);
    pthread_mutex_unlock(&mutex);
 }
void pthread_serv::run_clnt()
{
    int str_len;
    char str[1000];
    while ((str_len = read(clnt_sock,str,1000)) != 0)
       send_msg(str,str_len);
    pthread_mutex_lock(&mutex);
    clnt_sock_list.remove(clnt_sock);
    pthread_mutex_unlock(&mutex);
    close(clnt_sock);
}
 void* pthread_serv::hander_clnt(void *msg)
 {
     pthread_serv *serv = static_cast<pthread_serv*>(msg);
     serv->run_clnt();
 }
void pthread_serv::run()
{
    socklen_t clt_sz = sizeof(clnt_addr);
    while (true)
    {
        clnt_sock = accept(serv_sock,(sockaddr*)&clnt_addr,&clt_sz);
        fprintf(stdout,"new connect: %s\n",inet_ntoa(clnt_addr.sin_addr));
        pthread_create(&id_t,NULL,hander_clnt,this);
        pthread_detach(id_t);
        pthread_mutex_lock(&mutex);
        clnt_sock_list.push_back(clnt_sock);
        pthread_mutex_unlock(&mutex);

    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章