linux下的c++ 多執行緒封裝
阿新 • • 發佈:2019-02-20
最近為了學習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中這個可惡的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);
}
}