背景
在公司項目裏寫了個類,裏面簡單的流程就是,先讀取下本機名字和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,我太蠢了,所以同一段代碼,這臺沒問題,另一臺有問題。
總結
傳參數的時候,不,是所有涉及到類型不一致的時候,除非確定沒問題,否則類型要對應,不能瞎強轉。
寫一篇博客記錄這個愚蠢的問題,博君一笑~