1. 程式人生 > >linux下的c++ 多執行緒封裝

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);

    }
}