背景
在公司项目里写了个类,里面简单的流程就是,先读取下本机名字和IP,然后创建一个线程,差不多就是下面代码里的样子
class A
{
public:
void start()
{
// Get Hostname
char tmp_hostname[256];
gethostname(tmp_hostname, sizeof(tmp_hostname));
hostname = tmp_hostname;
// Get ip
hostent *host = gethostbyname(hostname.c_str());
ip = inet_ntoa(*(struct in_addr*)*host->h_addr_list);
// 注意这句话
pthread_create(pthread_create(reinterpret_cast<pthread_t *>(&thread_id), NULL, service_func, (void *)this);
}
void* server_func(void* args)
{
// service loop
while (1)
{}
return NULL;
}
private:
int thread_id;
string hostname;
string ip;
};
然后这段代码出现了segment fault,打印堆栈发现是hostname
出了问题,当时查了半天没查出来,因为是在项目里面,当时机子跑了别的任务,24核跑满了,编译起来特别慢,有些卡,就换了个机子把这段代码单独拿出来跑,结果怎么跑都没出现同样的问题,就很奇怪,诶,怎么同一段代码,放在别的机子上就好了呢。。。
最后没办法换了种写法,代码就好了,当时觉得是玄学。。。
发现问题
过了几天,在thread_id下面加了别的变量,写了点新东西,大概就是下面这个样子
class A
{
public:
...
private:
int thread_id;
char peer_ip[20];
};
然后这次发现,每次打印peer_ip
总是不对,但是只要在peer_ip
下面随便再搞个变量去用,就没有问题,这次结合上次的问题,突然发现。。。上次段错误好像是因为有地方把string的东西给改掉了,这次是有地方把peer_ip
给改掉了,唯一有可能改掉的地方就是用thread_id
的地方,因为peer_ip
我都是正常操作的。
查找thread_id
修改的唯一的地方,就是pthread_create
的地方,打印peer_ip
的每个字节,发现peer_ip
的前四个字节被改掉了。4+4就是8个字节。
问题所在
看下pthread_t是个unsigned long,然后突然反应过来,我项目运行的机器是装的64位的Debian,但是我的另一台没问题的机器是32位ubuntu,呃,突然发现问题觉得自己很蠢:
- 32位下的unsigned long是4字节的,所以用int给pthread_t用没有任何问题
- 64位下的unsigned long是8字节的,所以用int给pthread_t用少了4字节。。
以上导致了segment fault,我太蠢了,所以同一段代码,这台没问题,另一台有问题。
总结
传参数的时候,不,是所有涉及到类型不一致的时候,除非确定没问题,否则类型要对应,不能瞎强转。
写一篇博客记录这个愚蠢的问题,博君一笑~