C++ | C++多线程编程
2021/9/25 22:41:13
本文主要是介绍C++ | C++多线程编程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
C++ | C++多线程编程
C++ 多线程
多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序。
一般情况下,两种类型的多任务处理:基于进程和基于线程。
- 基于进程的
多任务处理
是程序的并发执行
。 - 基于线程的
多任务处理
是同一程序的片段的并发执行
。
创建线程
PTHREAD_CREATE(3) Linux Programmer's Manual PTHREAD_CREATE(3) NAME pthread_create - create a new thread SYNOPSIS #include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); Compile and link with -pthread. RETURN VALUE On success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined.
thread | 指向线程标识符的指针 |
---|---|
attr | 设置线程属性,NULL表示缺省 |
start_routine | 线程运行函数的起始地址 |
arg | 函数运行的参数 |
线程退出
PTHREAD_EXIT(3) Linux Programmer's Manual PTHREAD_EXIT(3) NAME pthread_exit - terminate calling thread SYNOPSIS #include <pthread.h> void pthread_exit(void *retval); Compile and link with -pthread. DESCRIPTION The pthread_exit() function terminates the calling thread and returns a value via retval that (if the thread is joinable) is available to another thread in the same process that calls pthread_join(3). Any clean-up handlers established by pthread_cleanup_push(3) that have not yet been popped, are popped (in the reverse of the order in which they were pushed) and executed. If the thread has any thread-specific data, then, after the clean-up handlers have been executed, the corresponding destructor functions are called, in an unspecified order. When a thread terminates, process-shared resources (e.g., mutexes, condition variables, semaphores, and file descriptors) are not released, and functions regis‐ tered using atexit(3) are not called. After the last thread in a process terminates, the process terminates as by calling exit(3) with an exit status of zero; thus, process-shared resources are re‐ leased and functions registered using atexit(3) are called. RETURN VALUE This function does not return to the caller. ERRORS This function always succeeds. CONFORMING TO POSIX.1-2001. NOTES Performing a return from the start function of any thread other than the main thread results in an implicit call to pthread_exit(), using the function's return value as the thread's exit status. To allow other threads to continue execution, the main thread should terminate by calling pthread_exit() rather than exit(3). The value pointed to by retval should not be located on the calling thread's stack, since the contents of that stack are undefined after the thread terminates. BUGS Currently, there are limitations in the kernel implementation logic for wait(2)ing on a stopped thread group with a dead thread group leader. This can manifest in problems such as a locked terminal if a stop signal is sent to a foreground process whose thread group leader has already called pthread_exit(). SEE ALSO pthread_create(3), pthread_join(3), pthreads(7) COLOPHON This page is part of release 3.55 of the Linux man-pages project. A description of the project, and information about reporting bugs, can be found at http://www.kernel.org/doc/man-pages/. Linux 2009-03-30 PTHREAD_EXIT(3)
实例1
/******************************************************************* * > File Name: thread.cpp * > Create Time: 2021年09月24日 11:50:02 ******************************************************************/ #include <iostream> #include <pthread.h> #include <unistd.h> using namespace std; #define NUM_PTHREAD (5) void* say(void *arg) { cout << "thread, arg:" << *(int*)arg << endl; return NULL; } int main(int argc, char* argv[]) { pthread_t thread[NUM_PTHREAD]; /* 定义5个线程标识符 */ for(int i; i< NUM_PTHREAD; i++) { pthread_create(&thread[i], NULL, say, (void*)&i); /* 创建线程 */ sleep(1); } pthread_exit(NULL); /* 结束线程 */ return 0; }
编译、运行:
PS E:\fly-prj\cplusplus\day18> make g++ -o thread thread.cpp -g -Wall -O0 -lpthread PS E:\fly-prj\cplusplus\day18> .\thread.exe thread, arg:1 thread, arg:2 thread, arg:3 thread, arg:4
实例2
/******************************************************************* * > File Name: thread1.cpp * > Create Time: 2021年09月24日 12:41:44 ******************************************************************/ #include <iostream> #include <pthread.h> #include <unistd.h> using namespace std; #define THREAD_NUM (5) void *say(void *args) { cout << " thread ID: " << *((int *)args) << endl; pthread_exit(NULL); return (void *)0; } int main(int argc, char* argv[]) { pthread_t thread[THREAD_NUM]; int indexs[THREAD_NUM]; for(int i = 0; i < THREAD_NUM; ++i) { cout << "main(), create thread " << i << endl; indexs[i] = i; if(pthread_create(&thread[i], NULL, say, (void *)&(indexs[i]))) { cout << "pthread_create error." << endl; return (-1); } sleep(1); } pthread_exit(NULL); return 0; }
编译、运行:
PS E:\fly-prj\cplusplus\day18> make g++ -o thread1 thread1.cpp -g -Wall -O0 -lpthread PS E:\fly-prj\cplusplus\day18> .\thread1.exe main(), create thread 0 thread ID: 0 main(), create thread 1 thread ID: 1 main(), create thread 2 thread ID: 2 main(), create thread 3 thread ID: 3 main(), create thread 4 thread ID: 4
向线程传递参数
实例3
/******************************************************************* * > File Name: thread_args.cpp * > Create Time: 2021年09月24日 13:03:15 ******************************************************************/ #include <iostream> #include <unistd.h> #include <pthread.h> using namespace std; #define THREAD_NUM (5) typedef struct thread_args{ int id; char *name; }THREAD_ARGS, *pTHREAD_ARGS; void* say(void *args) { /* 传递多个参数 */ cout << "id: " << ((pTHREAD_ARGS)args)->id << endl; cout << "name: " << ((pTHREAD_ARGS)args)->name << endl; pthread_exit(NULL); } int main(int argc, char* argv[]) { THREAD_ARGS args[THREAD_NUM]; pthread_t threadid[THREAD_NUM]; for(int i=0; i< THREAD_NUM; i++){ args[i].id = i; args[i].name = "Thread test."; threadid[i] = (pthread_t)i; if(pthread_create(&threadid[i], NULL, say, (void*)&args[i])){ cout << "pthread_create error." << endl;exit(-1); } sleep(1); // 不加,可能出现栈溢出 } pthread_exit(NULL); return 0; }
编译、运行:
PS E:\fly-prj\cplusplus\day18> make g++ -o thread_args thread_args.cpp -g -Wall -O0 -lpthread thread_args.cpp: 在函数‘int main(int, char**)’中: 33 | args[i].name = "Thread test."; | ^~~~~~~~~~~~~~ thread_args.cpp:34:22: 警告:将一个整数转换为大小不同的指针 [-Wint-to-pointer-cast] 34 | threadid[i] = (pthread_t)i; | ^~~~~~~~~~~~ PS E:\fly-prj\cplusplus\day18> .\thread_args.exe id: 0 name: Thread test. id: 1 name: Thread test. id: 2 name: Thread test. id: 3 name: Thread test. id: 4 name: Thread test.
连接和分离线程
int pthread_join(pthread_t thread, void **retval); //加入一个终止的线程
int pthread_detach(pthread_t thread); //分离线程
pthread_join()
子程序阻碍调用程序,直到指定的 threadid
线程终止为止。当创建一个线程时,它的某个属性会定义它是否是可连接的(joinable
)或可分离的(detached
)。只有创建时定义为可连接的线程才可以被连接。如果线程创建时被定义为可分离的,则它永远也不能被连接。
实例4
/******************************************************************* * > File Name: pthread.cpp * > Create Time: 2021年09月24日 23:43:58 ******************************************************************/ #include <iostream> #include <cstdlib> #include <pthread.h> #include <unistd.h> using namespace std; #define NUM_THREADS (5) void *wait(void *t) { long tid; tid = (long)t; sleep(1); cout << "Sleep in thread " << endl; cout << "Thread with id: " << tid << "...exiting" << endl; pthread_exit(NULL); } int main(int argc, char* argv[]) { int rc; int i; pthread_t threads[NUM_THREADS]; pthread_attr_t attr; void *status; pthread_attr_init(&attr); /*初始化线程属性对象*/ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); /* 设置线程的分离属性 */ for(i = 0; i< NUM_THREADS; i++){ cout << "main() : creating thread, " << i << endl; rc = pthread_create(&threads[i], NULL, wait, (void*)&i); /* 创建线程 */ if(rc){ cout << "Error: unable to create thread." << endl; exit(-1); } } // 删除属性,并等待其他线程 pthread_attr_destroy(&attr); for(i = 0; i< NUM_THREADS; i++){ rc = pthread_join(threads[i], &status); if(rc){ cout << "Error: unable to join, " << rc << endl; exit(-1); } cout << "Main: completed thread id :" << i; cout << " exiting with status: " << status << endl; } cout << "Main: program exiting." << endl; pthread_exit(NULL); /*结束当前线程*/ return 0; }
编译、运行:
PS D:\study\cplusplus\day9> make g++ -o pthread pthread.cpp -g -Wall -lpthread PS D:\study\cplusplus\day9> .\pthread.exe main() : creating thread, 0 main() : creating thread, 1 main() : creating thread, 2 main() : creating thread, 3 main() : creating thread, 4 Sleep in thread Sleep in thread Sleep in thread Sleep in thread Sleep in thread Thread with id: 4294953992Thread with id: Thread with id: Thread with id: Thread with id: ...exiting4294953992429495399242949539924294953992 ...exiting...exiting...exiting...exiting Main: completed thread id :0 exiting with status: 0 Main: completed thread id :1 exiting with status: 0 Main: completed thread id :2 exiting with status: 0 Main: completed thread id :3 exiting with status: 0 Main: completed thread id :4 exiting with status: 0 Main: program exiting.
C++ 11 标准线程库(std::thread
)
五个头文件:
<atomic>
引入std::atomic
和std::atomic_flag
,定义了原子操作<thread>
声明了std::thread
和std::this_thread
命名空间<mutex>
声明了与互斥量mutex
相关的类<condition_variable>
声明了与条件变量相关的类- 和
<future>
实例5
/******************************************************************* * > File Name: pthread1.cpp * > Create Time: 2021年09月25日 10:29:50 ******************************************************************/ #include <iostream> #include <thread> using namespace std; std::thread::id main_thread_id = std::this_thread::get_id(); void hello() { std::cout << "Hello Concurrent World\n"; if(main_thread_id == std::this_thread::get_id()){ std::cout << "This is the main thread.\n"; }else{ std::cout << "This is not the main thread."; } } void pause_thread(int n){ std::this_thread::sleep_for(std::chrono::seconds(n)); std::cout << "pause of " << n << "seconds ended\n"; } int main(int argc, char* argv[]) { std::thread t(hello); std::cout << t.hardware_concurrency() << std::endl; // 可以并发执行多个 std::cout << "native_handle" << t.native_handle() << std::endl; // 可以并发执行多个 t.join(); std::thread a(hello); a.detach(); std::thread threads[5]; /* 默认构造函数 */ std::cout << "Spawning 5 threads...\n" << endl; for(int i = 0; i< 5; i++){ threads[i] = std::thread(pause_thread, i+1); } std::cout << "Done spawning threads. Now waiting for them to join:\n"; for(auto &thread:threads){ thread.join(); } std::cout << "All threads joined\n"; return 0; }
编译、运行:
PS D:\study\cplusplus\day9> make g++ -o pthread pthread.cpp -g -Wall -std=c++11 -lpthread g++ -o pthread1 pthread1.cpp -g -Wall -std=c++11 -lpthread PS D:\study\cplusplus\day9> .\pthread1.exe Hello Concurrent World 4This is not the main thread. native_handle0x800074630 Hello Concurrent World Spawning 5 threads... This is not the main thread. Done spawning threads. Now waiting for them to join: pause of 1seconds ended pause of 2seconds ended pause of 3seconds ended pause of 4seconds ended pause of 5seconds ended All threads joined
std::thread
构造函数
默认构造函数 | thread() noexceped; |
---|---|
初始化构造函数 | template <class Fn, class ...Args> explicit thread(Fn&& fn, Args&&...args); |
拷贝构造函数[delected ] | thread(const thread &) = delete; |
Move 构造函数 | thread(thread&& x) noexcept; |
- 默认构造函数,创建一个空的
std::thread
执行对象。 - 初始化构造函数,创建一个
std::thread
对象,该std::thread
对象可被joinable
,新产生的线程会调用fn函数,该函数的参数由args
给出。 - 拷贝构造函数(被禁用),意味着
std::thread
对象不可拷贝构造。 Move
构造函数,move
构造函数(move
语义是C++11新出现的概念,详见附录),调用成功后x
不代表任何std::thread
执行对象。
注意:可被 joinable
的 std::thread
对象必须在他们销毁之前被主线程 join
或者将其设置为 detached
.
实例6
/******************************************************************* * > File Name: std_thread.cpp * > Create Time: 2021年09月25日 18:08:54 ******************************************************************/ #include <iostream> #include <utility> #include <thread> #include <chrono> #include <functional> #include <atomic> using namespace std; void f1(int n){ for(int i = 0; i< 5; ++i){ std::cout << "Thread f1 " << n << " executing\n"; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } void f2(int& n){ for(int i = 0; i< 5; ++i){ std::cout << "Thread f2 executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } int main(int argc, char* argv[]) { int n = 0; std::thread t1; // t1 is not a thread ,创建一个空的thread对象 std::thread t2(f1, n+1); // pass by value std::thread t3(f2, std::ref(n)); // pass by reference std::thread t4(std::move(t3)); // t4 is now running f2().t3 is no longer a thread t2.join(); t4.join(); std::cout << "Final value of n is " << n << "\n"; return 0; }
编译、运行:
PS D:\study\cplusplus\day9> make g++ -o std_thread std_thread.cpp -g -Wall -std=c++11 -lpthread PS D:\study\cplusplus\day9> .\std_thread.exe Thread f1 1 executing Thread f2 executing Thread f1 1 executing Thread f2 executing Thread f1 1 executing Thread f2 executing Thread f1 1 executing Thread f2 executing Thread f1 1 executing Thread f2 executing Final value of n is 5
std::thread
赋值操作
Move 赋值操作 | thread& operator=(thread&& rhs) noexcept; |
---|---|
拷贝赋值操作 [delected ] | thread& operator=(const thread&) = delete; |
Move
赋值操作(1),如果当前对象不可用joinable
,需传递一个右值引用(rhs
)给move
赋值操作;如果当前对象可被joinable
,则会调用terminate
()报错。- 拷贝赋值操作(2),被禁用,因此
std::thread
对象不可拷贝赋值。
c 多线程编程01
[线程模型、pthread 系列函数 和 简单多线程服务器端程序]
这篇关于C++ | C++多线程编程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-12深入理解 ECMAScript 2024 新特性:Map.groupBy() 分组操作
- 2025-01-11国产医疗级心电ECG采集处理模块
- 2025-01-10Rakuten 乐天积分系统从 Cassandra 到 TiDB 的选型与实战
- 2025-01-09CMS内容管理系统是什么?如何选择适合你的平台?
- 2025-01-08CCPM如何缩短项目周期并降低风险?
- 2025-01-08Omnivore 替代品 Readeck 安装与使用教程
- 2025-01-07Cursor 收费太贵?3分钟教你接入超低价 DeepSeek-V3,代码质量逼近 Claude 3.5
- 2025-01-06PingCAP 连续两年入选 Gartner 云数据库管理系统魔力象限“荣誉提及”
- 2025-01-05Easysearch 可搜索快照功能,看这篇就够了
- 2025-01-04BOT+EPC模式在基础设施项目中的应用与优势