Test thread

/*************************************************************************
    > File Name: ThreadBody.h
    > Author: wangzhicheng
    > Mail: 2363702560@qq.com
    > Created Time: 2017-01-06
    > Brief: abstract thread body
 ************************************************************************/
#ifndef THREAD_BODY_H
#define THREAD_BODY_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
namespace threadbody
{
using namespace std;
/* 
 * brief abstract thread class 
 * */  
class ThreadBody 
{  
public:  
	virtual void do_it() = 0;   // the real function which thread need to execute  
};
}

#endif

/*************************************************************************
    > File Name: main.cpp
    > Author: wangzhicheng
    > Mail: 2363702560@qq.com 
    > Created Time: Fri 06 Jan 2017 09:36:39 PM AWST
 ************************************************************************/

#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <functional>
#include "ThreadBody.h"
using namespace threadbody;
class ShowStr:public ThreadBody
{
public:
	ShowStr(const string &_str):str(_str)
	{
	}
	void do_it() 
	{
		cout << str << endl;
	}
private:
	string str;
};
class Processor
{
	private:
		int m_nThreadNum;
		ThreadBody *m_pThreadBody;
		vector<thread>m_ths;
	public:
		Processor(ThreadBody *p, int num = 2)
		{
			m_pThreadBody = p;
			m_nThreadNum = num;
			for(int i = 0;i < m_nThreadNum;i++)
			{
				m_ths.emplace_back(thread(bind(&ThreadBody::do_it, m_pThreadBody)));
			}
		}
		~Processor()
		{
			for(auto &th:m_ths)
			{
				if(th.joinable()) th.join();
			}
		}
};
int main()
{
	ShowStr ss("Hello World...!");
	Processor processor(&ss);
//	thread th(bind(&ThreadBody::do_it, &ss));
//	th.join();

	return 0;
}

CC=g++
all:
	$(CC) -std=c++11 -g -o TestThread main.cpp ThreadBody.h -pthread -lpthread


<think>好的,我需要详细解释用户提供的C代码中main()函数里创建线程的部分,并说明为什么这样创建。首先,我需要理解代码的结构和每个参数的作用。 用户提供的代码使用了pthread_create函数来创建一个线程,传递了参数arg作为整数520。在main函数中,调用pthread_create时,将arg转换为unsigned long long再转为void指针。而在test_thread函数中,又将void指针转换回int类型。 我需要分析为什么需要这样的类型转换。因为pthread_create的第四个参数是void指针,可以传递任意类型的数据,但int是基本数据类型,直接传递可能会导致类型不匹配的问题,特别是在64位系统上,int通常是4字节,而指针是8字节。直接将int转换为void指针可能会导致截断或符号扩展的问题,因此正确的做法是将int的地址传递给线程函数,或者将int值转换为足够大的整数类型(如intptr_t或uintptr_t)再转换为void指针。 但用户代码中使用的是将int转换为unsigned long long,然后再转为void指针。这可能是因为在64位系统上,unsigned long long是8字节,可以容纳int的值,避免截断。不过,更标准的做法是使用intptr_t或uintptr_t类型,这些类型专门设计用于指针和整数之间的转换,确保大小合适。 接下来,我需要检查代码是否存在潜在的问题。例如,如果arg是一个局部变量,传递其地址可能会导致线程访问时变量已销毁。但在这个例子中,arg是作为值传递的,所以不会有这个问题,但需要注意类型转换的正确性。 另外,用户可能想知道为什么不能直接将int转换为void指针而不经过unsigned long long的转换。这是因为在某些平台上,int可能无法直接转换为指针类型而不丢失信息,尤其是当int的大小小于指针的大小时(如32位到64位系统的差异)。 总结来说,用户代码中的转换方式是为了确保在不同平台上正确传递整数值,但更推荐使用标准类型如intptr_t来保证可移植性和正确性。同时,需要解释每个参数的作用和转换的必要性,以及可能的替代方法。</think>### **`main()` 函数中线程创建的详细解释** ```c res = pthread_create(&thread, NULL, test_thread, (void*)(unsigned long long)(arg)); ``` --- #### **1. 参数解析** | **参数** | **值** | **作用** | |--------------------|------------------------------------------------------------------------|--------------------------------------------------------------------------| | **`&thread`** | `pthread_t` 类型的指针,存储新线程的 ID | 用于后续操作线程(如 `pthread_join` 或 `pthread_cancel`)。 | | **`NULL`** | 默认线程属性 | 使用系统默认配置(如栈大小、调度策略)。 | | **`test_thread`** | 线程入口函数(函数指针) | 新线程启动后执行的代码。 | | **`(void*)(unsigned long long)(arg)`** | 将 `int` 类型的 `arg`(值为 520)转换为 `void*` 类型 | 传递整数参数给线程函数,避免类型不匹配问题。 | --- #### **2. 为什么要将 `int` 转换为 `void*`?** - **`pthread_create` 的限制**: 第四个参数 `arg` 是 `void*` 类型,只能传递指针(地址)。若直接传递 `int`(如 `arg` 是 `int`),需将其值转换为指针类型以避免编译警告或错误。 - **类型转换的必要性**: 在 64 位系统中: - `sizeof(int) = 4` 字节(32 位)。 - `sizeof(void*) = 8` 字节(64 位)。 - 直接将 `int` 转换为 `void*` 会导致隐式转换(如 `void* arg = (void*)520;`),但可能引发以下问题: - **截断风险**:若 `int` 的值超过 32 位,可能导致数据丢失(例如在 64 位系统中,符号扩展可能改变值)。 - **可移植性问题**:不同平台对指针与整数转换的处理可能不同。 - **解决方案**: 通过 `unsigned long long`(在 64 位系统中通常为 8 字节)中间转换,确保 `int` 的值完整传递: ```c (void*)(unsigned long long)(arg) // 先将 int 转为 64 位整数,再转为 void* ``` --- #### **3. 线程函数中如何获取参数?** 在 `test_thread` 中: ```c int num = (unsigned long long)arg; // 将 void* 转回 int ``` - **原因**: 需将 `void*` 参数还原为原始 `int` 类型。由于传递时已确保值完整(通过 `unsigned long long`),直接转换即可安全获取原始值。 --- #### **4. 更标准的替代方式** 虽然上述转换可行,但更推荐使用标准类型(如 `intptr_t` 或 `uintptr_t`),它们专门用于指针与整数的安全转换: ```c // 传递参数 res = pthread_create(&thread, NULL, test_thread, (void*)(intptr_t)arg); // 线程函数中 int num = (intptr_t)arg; ``` - **优势**: - `intptr_t` 和 `uintptr_t` 是 C99 标准定义的整数类型,保证与指针大小一致(如 64 位系统为 8 字节)。 - 避免平台依赖性问题,提高代码可移植性。 --- #### **5. 为什么不能直接传递 `int` 的地址?** 如果直接传递 `arg` 的地址(如 `&arg`),需注意: ```c res = pthread_create(&thread, NULL, test_thread, &arg); ``` - **风险**: - 若 `arg` 是局部变量(如 `main()` 中的 `int arg = 520;`),主线程可能在子线程访问前修改或销毁 `arg` 的值,导致数据竞争。 - 若需传递地址,应确保变量生命周期足够长(如使用 `malloc` 动态分配内存)。 --- #### **6. 完整流程总结** 1. **主线程**: - 定义变量 `arg = 520`。 - 将 `arg` 的值转换为 `void*` 类型(通过 `unsigned long long` 中间转换)。 - 调用 `pthread_create` 创建子线程,传递转换后的指针。 2. **子线程**: - 将 `void* arg` 转换回 `int` 类型。 - 打印参数值,模拟任务(如 `sleep(5)`),最后调用 `pthread_exit` 退出。 3. **主线程等待**: - 调用 `pthread_join` 等待子线程结束,确保资源回收。 --- #### **7. 代码潜在问题与改进建议** - **问题**: - 使用 `unsigned long long` 转换虽然可行,但依赖平台实现,可能在非 64 位系统上引发问题。 - **改进建议**: - 使用 `intptr_t` 或 `uintptr_t` 替代 `unsigned long long`,确保类型安全。 - 若参数为复杂结构体,应传递动态分配的堆内存地址(避免栈变量生命周期问题)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值