zoukankan      html  css  js  c++  java
  • cpp 线程传递参数

    给thread传递参数的 多种情况:

    在创建thread object时,可以向线程传递参数,默认情况下, 参数会被
    拷贝到 所创建的线程空间以供线程执行时存取,即使参数是引用也是这样.

    传递字面值

    void f(int i,const string& s);
    thread t(f,3,"hello");  // 字符串常量 "hello",会被转换成string,在新线程中存在.
    

    传递字符数组当字符串, 为了安全还是转换成 string 更好.

    void f(int f,const string& s);
    void oops(int some){
    	char buffer[1024];
    	sprintf(buffer,"%d",some);
    	thread t(f,3,buffer);  //  换成 thread t(f,3,string(buffer)); 保证安全
    	t.detach();
    }
    

    这里会存在一个潜在的风险,当oops退出时,新线程中,buffer可能还没有被转换成string,这将会出现一个dangle pointer.
    一个解决办法是 构造thread 时,就先将 buffer 转换成 string,并将string拷贝到新线程的地址空间.

    向线程传递一个引用, 注意需要使用 ref 函数

    class Test {
    public:
    	Test(int i = 0) :data(i) {}
    	Test(const Test& t) {
    		data = t.data;
    		cout << "Test copy constructor" << endl;
    	}
    	Test& operator=(const Test& t) {
    		data = t.data;
    		cout << "Test 赋值构造函数" << endl;
    		return *this;
    	}
    
    	~Test() {
    		cout << "Test deconstructor" << endl;
    	}
    
    public:
    	int data;
    };
    
    
    void func(Test& one) {
    	cout << "func get the data:" << one.data << endl;
    }
    
    void oops() {
    	Test one(10);
    
    	// windows 下 不使用ref编译不能通过,除非func方法里面的参数不是引用类型,但是这样会调用几次Test的拷贝构造函数.
    	thread t(func,ref(one));    
    
    	t.join();
    }
    
    int main()
    {
    	oops();
    	return 0;
    }
    

    thread 传递函数对象,需要注意,如果在 thread 构造参数里面构造对象,需要用"()"包起来

    class Testor {
    public:
    
    	Testor(int d = 0):data(d){}
    	Testor(const Testor& other) {
    		data = other.data;
    	}
    
    	Testor& operator=(const Testor& other) {
    		data = other.data;
    		return *this;
    	}
    
    	void operator()() {
    		cout << "Testor::operator() called!" << endl;
    	}
    
    public:
    	int data;
    };
    
    void oops() {
    	thread t((Testor()));  // Test() 必须用"()"包起来,否则windows下编译不通过
    	t.join();
    }
    
    int main()
    {
    	oops();
    	return 0;
    }
    

    仿照 bind 将对象的成员函数作为线程的参数

    class Testor {
    public:
    
    	Testor(int d = 0):data(d){}
    	Testor(const Testor& other) {
    		data = other.data;
    	}
    
    	Testor& operator=(const Testor& other) {
    		data = other.data;
    		return *this;
    	}
    
    	void operator()() {
    		cout << "Testor::operator() called!" << endl;
    	}
    
    	void show() {
    		cout << "Testor show called!" << endl;
    	}
    
    public:
    	int data;
    };
    
    void oops() {
    	Testor testor;
    	thread t(&Testor::show,&testor);
    	t.join();
    }
    
    int main()
    {
    	oops();
    	return 0;
    }
    

    向thread传递指针:普通指针和智能指针, 需要注意安全

    class Testor {
    public:
    
    	Testor(int d = 0):data(d){}
    	Testor(const Testor& other) {
    		data = other.data;
    	}
    
    	Testor& operator=(const Testor& other) {
    		data = other.data;
    		return *this;
    	}
    
    	~Testor() {
    		cout << "~Testor called!" << endl;
    	}
    
    	void operator()() {
    		cout << "Testor::operator() called!" << endl;
    	}
    
    	void show() {
    		cout << "Testor show called!" << endl;
    	}
    
    public:
    	int data;
    };
    
    void func_1(shared_ptr<Testor> ptr) {
    	ptr->data++;
    }
    
    void func_2(Testor* ptr) {
    	ptr->data++;
    }
    
    void oops() {
    	shared_ptr<Testor> ptr(new Testor(11));
    	thread t1(func_1,ptr);
    	t1.join();
    	cout << "shared_ptr->data:" << ptr->data << endl;
    
    	auto ptr2 = new Testor(11);
    	thread t2(func_2, ptr2);
    	t2.join();
    	cout << "ptr2->data:" << ptr2->data << endl;
    	delete ptr2;
    }
    
    int main()
    {
    	oops();
    	return 0;
    }
    

    说明:传递指针给线程函数, thread 拷贝的是指针对象本身,所以线程怼指针对象的修改会影响到
    主线程中的对象.
    注意,智能指针可能会引起对象的生命周期的延长,若是 thread::detach,那么智能指针比普通的
    裸指针安全,特别是detach后oops退出,智能指针管理的对象由于引用计数不会被析构,而普通裸
    指针由于oops退出析构了局部对象导致dangle pointer.

    unique_ptr的movable语义传递参数, 需要使用 move 函数

    class Testor {
    public:
    
    	Testor(int d = 0):data(d){}
    	Testor(const Testor& other) {
    		data = other.data;
    	}
    
    	Testor& operator=(const Testor& other) {
    		data = other.data;
    		return *this;
    	}
    
    	~Testor() {
    		cout << "~Testor called!" << endl;
    	}
    
    	void operator()() {
    		cout << "Testor::operator() called!" << endl;
    	}
    
    	void show() {
    		cout << "Testor show called!" << endl;
    	}
    
    public:
    	int data;
    };
    
    void func_1(shared_ptr<Testor> ptr) {
    	ptr->data++;
    }
    
    void func_2(Testor* ptr) {
    	ptr->data++;
    }
    
    void func_3(unique_ptr<Testor> uptr) {
    	uptr->data = 44;
    	cout << "func_3->data:" << uptr->data << endl;
    }
    
    void oops() {
    	
    	unique_ptr<Testor> uptr(new Testor(11));
    
    	// 必须要使用 move,否则 windows下编译不过.
    	// 因为unique_ptr是个左值对象,move的功能是将左值变成右值使用
    	thread t(func_3,move(uptr)); 
    	t.join();
    
    	if (uptr.get()) {
    		cout << "main thread:" << uptr->data << endl;
    	}
    	else {
    		cout << "main thread uptr is null!" << endl;  // 将会被打印
    	}
    }
    
    int main()
    {
    	oops();
    	return 0;
    }
    

    说明:std::unique_ptr不能共享所有权,但是可以转移所有权,
    采用std::move()语义后原来的std::unique_ptr 将为null.

    总结来自:https://blog.csdn.net/liuxuejiang158blog/article/details/17090971

  • 相关阅读:
    ASP.NET Core 中的管道机制
    常见的 HttpModule
    IIS+Asp.Net Mvc必须知道的事(解决启动/重启/自动回收站点后第一次访问慢问题)
    ASP.NET三剑客 HttpApplication HttpModule HttpHandler 解析
    Js国际化
    MethodImplOptions
    Java守护线程普通线程的例子
    Java启动新线程的几种方式(Runnable、Callable、CompletableFuture)
    Tomcat源码分析(3)-容器Container整体架构
    Tomcat源码分析(2)-连接器Connector整体架构
  • 原文地址:https://www.cnblogs.com/daihanlong/p/10261433.html
Copyright © 2011-2022 走看看