├── README.md ├── SingleInstance ├── Resource.h ├── SingleInstance.cpp ├── SingleInstance.h ├── SingleInstance.ico ├── SingleInstance.rc ├── SingleInstance.sln ├── SingleInstance.vcxproj ├── SingleInstance.vcxproj.filters ├── small.ico ├── stdafx.cpp ├── stdafx.h └── targetver.h ├── TaskPool.cpp ├── TaskPool.h ├── TestFiber.cpp ├── articlelog.jpg ├── c11mutex.cpp ├── c11threadlocal.cpp ├── cpp11cv.cpp ├── cv.cpp ├── insecurecrtfunction.cpp ├── linuxtid.cpp ├── linuxtls.cpp ├── linuxtls2.cpp ├── makesurethread.cpp ├── makesurethreadgroup.cpp ├── rwlock.cpp ├── rwlock2.cpp ├── rwlock3.cpp ├── semaphore.cpp ├── semaphore_timewait.cpp ├── taskpoolmain.cpp └── windowstls.cpp /README.md: -------------------------------------------------------------------------------- 1 | # gitchat_cppmultithreadprogramming 2 | gitchat 《C++ 多线程编程详解》课程源码 3 | 4 | 如果你在学习这个课程的过程中有任何疑问也可以加入高性能服务器学习 QQ 群:**729995516** 交流。 5 | 6 | 7 | -------------------------------------------------------------------------------- /SingleInstance/Resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by SingleInstance.rc 4 | // 5 | 6 | #define IDS_APP_TITLE 103 7 | 8 | #define IDR_MAINFRAME 128 9 | #define IDD_SINGLEINSTANCE_DIALOG 102 10 | #define IDD_ABOUTBOX 103 11 | #define IDM_ABOUT 104 12 | #define IDM_EXIT 105 13 | #define IDI_SINGLEINSTANCE 107 14 | #define IDI_SMALL 108 15 | #define IDC_SINGLEINSTANCE 109 16 | #define IDC_MYICON 2 17 | #ifndef IDC_STATIC 18 | #define IDC_STATIC -1 19 | #endif 20 | // Next default values for new objects 21 | // 22 | #ifdef APSTUDIO_INVOKED 23 | #ifndef APSTUDIO_READONLY_SYMBOLS 24 | 25 | #define _APS_NO_MFC 130 26 | #define _APS_NEXT_RESOURCE_VALUE 129 27 | #define _APS_NEXT_COMMAND_VALUE 32771 28 | #define _APS_NEXT_CONTROL_VALUE 1000 29 | #define _APS_NEXT_SYMED_VALUE 110 30 | #endif 31 | #endif 32 | -------------------------------------------------------------------------------- /SingleInstance/SingleInstance.cpp: -------------------------------------------------------------------------------- 1 | // SingleInstance.cpp : Defines the entry point for the application. 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "SingleInstance.h" 6 | 7 | #define MAX_LOADSTRING 100 8 | 9 | // Global Variables: 10 | HINSTANCE hInst; // current instance 11 | TCHAR szTitle[MAX_LOADSTRING]; // The title bar text 12 | TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name 13 | 14 | // Forward declarations of functions included in this code module: 15 | ATOM MyRegisterClass(HINSTANCE hInstance); 16 | BOOL InitInstance(HINSTANCE, int); 17 | LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 18 | INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); 19 | 20 | bool CheckInstance() 21 | { 22 | HANDLE hSingleInstanceMutex = CreateMutex(NULL, FALSE, _T("MySingleInstanceApp")); 23 | if (hSingleInstanceMutex != NULL) 24 | { 25 | if (GetLastError() == ERROR_ALREADY_EXISTS) 26 | { 27 | return true; 28 | } 29 | } 30 | 31 | return false; 32 | } 33 | 34 | int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, 35 | _In_opt_ HINSTANCE hPrevInstance, 36 | _In_ LPTSTR lpCmdLine, 37 | _In_ int nCmdShow) 38 | { 39 | UNREFERENCED_PARAMETER(hPrevInstance); 40 | UNREFERENCED_PARAMETER(lpCmdLine); 41 | 42 | LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 43 | LoadString(hInstance, IDC_SINGLEINSTANCE, szWindowClass, MAX_LOADSTRING); 44 | 45 | if (CheckInstance()) 46 | { 47 | HWND hwndPre = FindWindow(szWindowClass, NULL); 48 | if (IsWindow(hwndPre)) 49 | { 50 | if (::IsIconic(hwndPre)) 51 | ::SendMessage(hwndPre, WM_SYSCOMMAND, SC_RESTORE | HTCAPTION, 0); 52 | 53 | ::SetWindowPos(hwndPre, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE); 54 | ::SetForegroundWindow(hwndPre); 55 | ::SetFocus(hwndPre); 56 | return 0; 57 | } 58 | } 59 | 60 | // TODO: Place code here. 61 | MSG msg; 62 | HACCEL hAccelTable; 63 | 64 | // Initialize global strings 65 | 66 | MyRegisterClass(hInstance); 67 | 68 | // Perform application initialization: 69 | if (!InitInstance (hInstance, nCmdShow)) 70 | { 71 | return FALSE; 72 | } 73 | 74 | hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SINGLEINSTANCE)); 75 | 76 | // Main message loop: 77 | while (GetMessage(&msg, NULL, 0, 0)) 78 | { 79 | if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 80 | { 81 | TranslateMessage(&msg); 82 | DispatchMessage(&msg); 83 | } 84 | } 85 | 86 | return (int) msg.wParam; 87 | } 88 | 89 | 90 | 91 | // 92 | // FUNCTION: MyRegisterClass() 93 | // 94 | // PURPOSE: Registers the window class. 95 | // 96 | ATOM MyRegisterClass(HINSTANCE hInstance) 97 | { 98 | WNDCLASSEX wcex; 99 | 100 | wcex.cbSize = sizeof(WNDCLASSEX); 101 | 102 | wcex.style = CS_HREDRAW | CS_VREDRAW; 103 | wcex.lpfnWndProc = WndProc; 104 | wcex.cbClsExtra = 0; 105 | wcex.cbWndExtra = 0; 106 | wcex.hInstance = hInstance; 107 | wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SINGLEINSTANCE)); 108 | wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 109 | wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 110 | wcex.lpszMenuName = MAKEINTRESOURCE(IDC_SINGLEINSTANCE); 111 | wcex.lpszClassName = szWindowClass; 112 | wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); 113 | 114 | return RegisterClassEx(&wcex); 115 | } 116 | 117 | // 118 | // FUNCTION: InitInstance(HINSTANCE, int) 119 | // 120 | // PURPOSE: Saves instance handle and creates main window 121 | // 122 | // COMMENTS: 123 | // 124 | // In this function, we save the instance handle in a global variable and 125 | // create and display the main program window. 126 | // 127 | BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) 128 | { 129 | HWND hWnd; 130 | 131 | hInst = hInstance; // Store instance handle in our global variable 132 | 133 | hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, 134 | CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); 135 | 136 | if (!hWnd) 137 | { 138 | return FALSE; 139 | } 140 | 141 | ShowWindow(hWnd, nCmdShow); 142 | UpdateWindow(hWnd); 143 | 144 | return TRUE; 145 | } 146 | 147 | // 148 | // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) 149 | // 150 | // PURPOSE: Processes messages for the main window. 151 | // 152 | // WM_COMMAND - process the application menu 153 | // WM_PAINT - Paint the main window 154 | // WM_DESTROY - post a quit message and return 155 | // 156 | // 157 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 158 | { 159 | int wmId, wmEvent; 160 | PAINTSTRUCT ps; 161 | HDC hdc; 162 | 163 | switch (message) 164 | { 165 | case WM_COMMAND: 166 | wmId = LOWORD(wParam); 167 | wmEvent = HIWORD(wParam); 168 | // Parse the menu selections: 169 | switch (wmId) 170 | { 171 | case IDM_ABOUT: 172 | DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); 173 | break; 174 | case IDM_EXIT: 175 | DestroyWindow(hWnd); 176 | break; 177 | default: 178 | return DefWindowProc(hWnd, message, wParam, lParam); 179 | } 180 | break; 181 | case WM_PAINT: 182 | hdc = BeginPaint(hWnd, &ps); 183 | // TODO: Add any drawing code here... 184 | EndPaint(hWnd, &ps); 185 | break; 186 | case WM_DESTROY: 187 | PostQuitMessage(0); 188 | break; 189 | default: 190 | return DefWindowProc(hWnd, message, wParam, lParam); 191 | } 192 | return 0; 193 | } 194 | 195 | // Message handler for about box. 196 | INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 197 | { 198 | UNREFERENCED_PARAMETER(lParam); 199 | switch (message) 200 | { 201 | case WM_INITDIALOG: 202 | return (INT_PTR)TRUE; 203 | 204 | case WM_COMMAND: 205 | if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 206 | { 207 | EndDialog(hDlg, LOWORD(wParam)); 208 | return (INT_PTR)TRUE; 209 | } 210 | break; 211 | } 212 | return (INT_PTR)FALSE; 213 | } 214 | -------------------------------------------------------------------------------- /SingleInstance/SingleInstance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "resource.h" 4 | -------------------------------------------------------------------------------- /SingleInstance/SingleInstance.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/gitchat_cppmultithreadprogramming/03542070470fbd39a05aad2f310d9f9bdf373d6a/SingleInstance/SingleInstance.ico -------------------------------------------------------------------------------- /SingleInstance/SingleInstance.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/gitchat_cppmultithreadprogramming/03542070470fbd39a05aad2f310d9f9bdf373d6a/SingleInstance/SingleInstance.rc -------------------------------------------------------------------------------- /SingleInstance/SingleInstance.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SingleInstance", "SingleInstance.vcxproj", "{83BFFE4B-7CE2-4D8D-873D-C5CF8E353B85}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {83BFFE4B-7CE2-4D8D-873D-C5CF8E353B85}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {83BFFE4B-7CE2-4D8D-873D-C5CF8E353B85}.Debug|Win32.Build.0 = Debug|Win32 16 | {83BFFE4B-7CE2-4D8D-873D-C5CF8E353B85}.Release|Win32.ActiveCfg = Release|Win32 17 | {83BFFE4B-7CE2-4D8D-873D-C5CF8E353B85}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /SingleInstance/SingleInstance.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {83BFFE4B-7CE2-4D8D-873D-C5CF8E353B85} 15 | Win32Proj 16 | SingleInstance 17 | 18 | 19 | 20 | Application 21 | true 22 | v120 23 | Unicode 24 | 25 | 26 | Application 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | Use 51 | Level3 52 | Disabled 53 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 54 | true 55 | 56 | 57 | Windows 58 | true 59 | 60 | 61 | 62 | 63 | Level3 64 | Use 65 | MaxSpeed 66 | true 67 | true 68 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 69 | true 70 | 71 | 72 | Windows 73 | true 74 | true 75 | true 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | Create 91 | Create 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /SingleInstance/SingleInstance.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | 43 | 44 | Resource Files 45 | 46 | 47 | 48 | 49 | Resource Files 50 | 51 | 52 | Resource Files 53 | 54 | 55 | -------------------------------------------------------------------------------- /SingleInstance/small.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/gitchat_cppmultithreadprogramming/03542070470fbd39a05aad2f310d9f9bdf373d6a/SingleInstance/small.ico -------------------------------------------------------------------------------- /SingleInstance/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // SingleInstance.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /SingleInstance/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | // Windows Header Files: 12 | #include 13 | 14 | // C RunTime Header Files 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | // TODO: reference additional headers your program requires here 22 | -------------------------------------------------------------------------------- /SingleInstance/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /TaskPool.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/gitchat_cppmultithreadprogramming/03542070470fbd39a05aad2f310d9f9bdf373d6a/TaskPool.cpp -------------------------------------------------------------------------------- /TaskPool.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/gitchat_cppmultithreadprogramming/03542070470fbd39a05aad2f310d9f9bdf373d6a/TaskPool.h -------------------------------------------------------------------------------- /TestFiber.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/gitchat_cppmultithreadprogramming/03542070470fbd39a05aad2f310d9f9bdf373d6a/TestFiber.cpp -------------------------------------------------------------------------------- /articlelog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/gitchat_cppmultithreadprogramming/03542070470fbd39a05aad2f310d9f9bdf373d6a/articlelog.jpg -------------------------------------------------------------------------------- /c11mutex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // protected by g_num_mutex 7 | int g_num = 0; 8 | std::mutex g_num_mutex; 9 | 10 | void slow_increment(int id) 11 | { 12 | for (int i = 0; i < 3; ++i) { 13 | g_num_mutex.lock(); 14 | ++g_num; 15 | std::cout << id << " => " << g_num << std::endl; 16 | g_num_mutex.unlock(); 17 | 18 | //sleep for 1 second 19 | std::this_thread::sleep_for(std::chrono::seconds(1)); 20 | } 21 | } 22 | 23 | int main() 24 | { 25 | std::thread t1(slow_increment, 0); 26 | std::thread t2(slow_increment, 1); 27 | t1.join(); 28 | t2.join(); 29 | 30 | return 0; 31 | } -------------------------------------------------------------------------------- /c11threadlocal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | thread_local int g_mydata = 1; 6 | 7 | void thread_func1() 8 | { 9 | while (true) 10 | { 11 | ++g_mydata; 12 | } 13 | } 14 | 15 | void thread_func2() 16 | { 17 | while (true) 18 | { 19 | std::cout << "g_mydata = " << g_mydata << ", ThreadID = " << std::this_thread::get_id() << std::endl; 20 | std::this_thread::sleep_for(std::chrono::seconds(1)); 21 | } 22 | } 23 | 24 | int main() 25 | { 26 | std::thread t1(thread_func1); 27 | std::thread t2(thread_func2); 28 | 29 | t1.join(); 30 | t2.join(); 31 | 32 | return 0; 33 | } -------------------------------------------------------------------------------- /cpp11cv.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class Task 10 | { 11 | public: 12 | Task(int taskID) 13 | { 14 | this->taskID = taskID; 15 | } 16 | 17 | void doTask() 18 | { 19 | std::cout << "handle a task, taskID: " << taskID << ", threadID: " << std::this_thread::get_id() << std::endl; 20 | } 21 | 22 | private: 23 | int taskID; 24 | }; 25 | 26 | std::mutex mymutex; 27 | std::list tasks; 28 | std::condition_variable mycv; 29 | 30 | void* consumer_thread() 31 | { 32 | Task* pTask = NULL; 33 | while (true) 34 | { 35 | std::unique_lock guard(mymutex); 36 | while (tasks.empty()) 37 | { 38 | //如果获得了互斥锁,但是条件不合适的话,pthread_cond_wait会释放锁,不往下执行。 39 | //当发生变化后,条件合适,pthread_cond_wait将直接获得锁。 40 | mycv.wait(guard); 41 | } 42 | 43 | pTask = tasks.front(); 44 | tasks.pop_front(); 45 | 46 | if (pTask == NULL) 47 | continue; 48 | 49 | pTask->doTask(); 50 | delete pTask; 51 | pTask = NULL; 52 | } 53 | 54 | return NULL; 55 | } 56 | 57 | void* producer_thread() 58 | { 59 | int taskID = 0; 60 | Task* pTask = NULL; 61 | 62 | while (true) 63 | { 64 | pTask = new Task(taskID); 65 | 66 | //使用括号减小guard锁的作用范围 67 | { 68 | std::lock_guard guard(mymutex); 69 | tasks.push_back(pTask); 70 | std::cout << "produce a task, taskID: " << taskID << ", threadID: " << std::this_thread::get_id() << std::endl; 71 | } 72 | 73 | //释放信号量,通知消费者线程 74 | mycv.notify_one(); 75 | 76 | taskID ++; 77 | 78 | //休眠1秒 79 | std::this_thread::sleep_for(std::chrono::seconds(1)); 80 | } 81 | 82 | return NULL; 83 | } 84 | 85 | int main() 86 | { 87 | //创建5个消费者线程 88 | std::thread consumer1(consumer_thread); 89 | std::thread consumer2(consumer_thread); 90 | std::thread consumer3(consumer_thread); 91 | std::thread consumer4(consumer_thread); 92 | std::thread consumer5(consumer_thread); 93 | 94 | //创建一个生产者线程 95 | std::thread producer(producer_thread); 96 | 97 | producer.join(); 98 | consumer1.join(); 99 | consumer2.join(); 100 | consumer3.join(); 101 | consumer4.join(); 102 | consumer5.join(); 103 | 104 | return 0; 105 | } -------------------------------------------------------------------------------- /cv.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class Task 9 | { 10 | public: 11 | Task(int taskID) 12 | { 13 | this->taskID = taskID; 14 | } 15 | 16 | void doTask() 17 | { 18 | std::cout << "handle a task, taskID: " << taskID << ", threadID: " << pthread_self() << std::endl; 19 | } 20 | 21 | private: 22 | int taskID; 23 | }; 24 | 25 | pthread_mutex_t mymutex; 26 | std::list tasks; 27 | pthread_cond_t mycv; 28 | 29 | void* consumer_thread(void* param) 30 | { 31 | Task* pTask = NULL; 32 | while (true) 33 | { 34 | pthread_mutex_lock(&mymutex); 35 | while (tasks.empty()) 36 | { 37 | //如果获得了互斥锁,但是条件不合适的话,pthread_cond_wait会释放锁,不往下执行。 38 | //当发生变化后,条件合适,pthread_cond_wait将直接获得锁。 39 | pthread_cond_wait(&mycv, &mymutex); 40 | } 41 | 42 | pTask = tasks.front(); 43 | tasks.pop_front(); 44 | 45 | pthread_mutex_unlock(&mymutex); 46 | 47 | if (pTask == NULL) 48 | continue; 49 | 50 | pTask->doTask(); 51 | delete pTask; 52 | pTask = NULL; 53 | } 54 | 55 | return NULL; 56 | } 57 | 58 | void* producer_thread(void* param) 59 | { 60 | int taskID = 0; 61 | Task* pTask = NULL; 62 | 63 | while (true) 64 | { 65 | pTask = new Task(taskID); 66 | 67 | pthread_mutex_lock(&mymutex); 68 | tasks.push_back(pTask); 69 | std::cout << "produce a task, taskID: " << taskID << ", threadID: " << pthread_self() << std::endl; 70 | 71 | pthread_mutex_unlock(&mymutex); 72 | 73 | //释放条件信号,通知消费者线程 74 | pthread_cond_signal(&mycv); 75 | 76 | taskID ++; 77 | 78 | //休眠1秒 79 | sleep(1); 80 | } 81 | 82 | return NULL; 83 | } 84 | 85 | int main() 86 | { 87 | pthread_mutex_init(&mymutex, NULL); 88 | pthread_cond_init(&mycv, NULL); 89 | 90 | //创建5个消费者线程 91 | pthread_t consumerThreadID[5]; 92 | for (int i = 0; i < 5; ++i) 93 | { 94 | pthread_create(&consumerThreadID[i], NULL, consumer_thread, NULL); 95 | } 96 | 97 | //创建一个生产者线程 98 | pthread_t producerThreadID; 99 | pthread_create(&producerThreadID, NULL, producer_thread, NULL); 100 | 101 | pthread_join(producerThreadID, NULL); 102 | 103 | for (int i = 0; i < 5; ++i) 104 | { 105 | pthread_join(consumerThreadID[i], NULL); 106 | } 107 | 108 | pthread_cond_destroy(&mycv); 109 | pthread_mutex_destroy(&mymutex); 110 | 111 | return 0; 112 | } -------------------------------------------------------------------------------- /insecurecrtfunction.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/balloonwj/gitchat_cppmultithreadprogramming/03542070470fbd39a05aad2f310d9f9bdf373d6a/insecurecrtfunction.cpp -------------------------------------------------------------------------------- /linuxtid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void* thread_proc(void* arg) 7 | { 8 | pthread_t* tid1 = (pthread_t*)arg; 9 | int tid2 = syscall(SYS_gettid); 10 | pthread_t tid3 = pthread_self(); 11 | 12 | while(true) 13 | { 14 | printf("tid1: %ld, tid2: %ld, tid3: %ld\n", *tid1, tid2, tid3); 15 | sleep(1); 16 | } 17 | 18 | } 19 | 20 | int main() 21 | { 22 | pthread_t tid; 23 | pthread_create(&tid, NULL, thread_proc, &tid); 24 | 25 | pthread_join(tid, NULL); 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /linuxtls.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //线程局部存储key 6 | pthread_key_t thread_log_key; 7 | 8 | void write_to_thread_log(const char* message) 9 | { 10 | if (message == NULL) 11 | return; 12 | 13 | FILE* logfile = (FILE*)pthread_getspecific(thread_log_key); 14 | fprintf(logfile, "%s\n", message); 15 | fflush(logfile); 16 | } 17 | 18 | void close_thread_log(void* logfile) 19 | { 20 | char logfilename[128]; 21 | sprintf(logfilename, "close logfile: thread%ld.log\n", (unsigned long)pthread_self()); 22 | printf(logfilename); 23 | 24 | fclose((FILE *)logfile); 25 | } 26 | 27 | void* thread_function(void* args) 28 | { 29 | char logfilename[128]; 30 | sprintf(logfilename, "thread%ld.log", (unsigned long)pthread_self()); 31 | 32 | FILE* logfile = fopen(logfilename, "w"); 33 | if (logfile != NULL) 34 | { 35 | pthread_setspecific(thread_log_key, logfile); 36 | 37 | write_to_thread_log("Thread starting..."); 38 | } 39 | 40 | return NULL; 41 | } 42 | 43 | int main() 44 | { 45 | pthread_t threadIDs[5]; 46 | pthread_key_create(&thread_log_key, close_thread_log); 47 | for(int i = 0; i < 5; ++i) 48 | { 49 | pthread_create(&threadIDs[i], NULL, thread_function, NULL); 50 | } 51 | 52 | for(int i = 0; i < 5; ++i) 53 | { 54 | pthread_join(threadIDs[i], NULL); 55 | } 56 | 57 | return 0; 58 | } -------------------------------------------------------------------------------- /linuxtls2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //线程局部存储key 6 | __thread int g_mydata = 99; 7 | 8 | void* thread_function1(void* args) 9 | { 10 | while (true) 11 | { 12 | g_mydata ++; 13 | } 14 | 15 | return NULL; 16 | } 17 | 18 | void* thread_function2(void* args) 19 | { 20 | while (true) 21 | { 22 | std::cout << "g_mydata = " << g_mydata << ", ThreadID: " << pthread_self() << std::endl; 23 | sleep(1); 24 | } 25 | 26 | return NULL; 27 | } 28 | 29 | int main() 30 | { 31 | pthread_t threadIDs[2]; 32 | pthread_create(&threadIDs[0], NULL, thread_function1, NULL); 33 | pthread_create(&threadIDs[1], NULL, thread_function2, NULL); 34 | 35 | for(int i = 0; i < 2; ++i) 36 | { 37 | pthread_join(threadIDs[i], NULL); 38 | } 39 | 40 | return 0; 41 | } -------------------------------------------------------------------------------- /makesurethread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | std::mutex mymutex; 7 | std::condition_variable mycv; 8 | bool success = false; 9 | 10 | void thread_func() 11 | { 12 | { 13 | std::unique_lock lock(mymutex); 14 | success = true; 15 | mycv.notify_all(); 16 | } 17 | 18 | //实际的线程执行的工作代码放在下面 19 | //这里为了模拟方便,简单地写个死循环 20 | while (true) 21 | { 22 | 23 | } 24 | } 25 | 26 | int main() 27 | { 28 | std::thread t(thread_func); 29 | 30 | //使用花括号减小锁的粒度 31 | { 32 | std::unique_lock lock(mymutex); 33 | while (!success) 34 | { 35 | mycv.wait(lock); 36 | } 37 | } 38 | 39 | std::cout << "start thread successfully." << std::endl; 40 | 41 | t.join(); 42 | 43 | return 0; 44 | } -------------------------------------------------------------------------------- /makesurethreadgroup.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::mutex mymutex; 9 | std::condition_variable mycv; 10 | bool success = false; 11 | 12 | void thread_func() 13 | { 14 | { 15 | std::unique_lock lock(mymutex); 16 | success = true; 17 | mycv.notify_all(); 18 | } 19 | 20 | //实际的线程执行的工作代码放在下面 21 | //这里为了模拟方便,简单地写个死循环 22 | while (true) 23 | { 24 | 25 | } 26 | } 27 | 28 | int main() 29 | { 30 | std::vector> threads; 31 | 32 | for (int i = 0; i < 5; ++i) 33 | { 34 | std::shared_ptr spthread; 35 | spthread.reset(new std::thread(thread_func)); 36 | 37 | //使用花括号减小锁的粒度 38 | { 39 | std::unique_lock lock(mymutex); 40 | while (!success) 41 | { 42 | mycv.wait(lock); 43 | } 44 | } 45 | 46 | std::cout << "start thread successfully, index: " << i << std::endl; 47 | 48 | threads.push_back(spthread); 49 | } 50 | 51 | for (auto& iter : threads) 52 | { 53 | iter->join(); 54 | } 55 | 56 | return 0; 57 | } -------------------------------------------------------------------------------- /rwlock.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int resourceID = 0; 6 | pthread_rwlock_t myrwlock; 7 | 8 | void* read_thread(void* param) 9 | { 10 | while (true) 11 | { 12 | //请求读锁 13 | pthread_rwlock_rdlock(&myrwlock); 14 | 15 | std::cout << "read thread ID: " << pthread_self() << ", resourceID: " << resourceID << std::endl; 16 | 17 | //使用睡眠模拟读线程读的过程消耗了很久的时间 18 | sleep(1); 19 | 20 | pthread_rwlock_unlock(&myrwlock); 21 | } 22 | 23 | return NULL; 24 | } 25 | 26 | void* write_thread(void* param) 27 | { 28 | while (true) 29 | { 30 | //请求写锁 31 | pthread_rwlock_wrlock(&myrwlock); 32 | 33 | ++resourceID; 34 | std::cout << "write thread ID: " << pthread_self() << ", resourceID: " << resourceID << std::endl; 35 | 36 | //使用睡眠模拟读线程读的过程消耗了很久的时间 37 | sleep(1); 38 | 39 | pthread_rwlock_unlock(&myrwlock); 40 | } 41 | 42 | return NULL; 43 | } 44 | 45 | int main() 46 | { 47 | pthread_rwlock_init(&myrwlock, NULL); 48 | 49 | //创建5个请求读锁线程 50 | pthread_t readThreadID[5]; 51 | for (int i = 0; i < 5; ++i) 52 | { 53 | pthread_create(&readThreadID[i], NULL, read_thread, NULL); 54 | } 55 | 56 | //创建一个请求写锁线程 57 | pthread_t writeThreadID; 58 | pthread_create(&writeThreadID, NULL, write_thread, NULL); 59 | 60 | pthread_join(writeThreadID, NULL); 61 | 62 | for (int i = 0; i < 5; ++i) 63 | { 64 | pthread_join(readThreadID[i], NULL); 65 | } 66 | 67 | pthread_rwlock_destroy(&myrwlock); 68 | 69 | return 0; 70 | } -------------------------------------------------------------------------------- /rwlock2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int resourceID = 0; 6 | pthread_rwlock_t myrwlock; 7 | 8 | void* read_thread(void* param) 9 | { 10 | while (true) 11 | { 12 | //请求读锁 13 | pthread_rwlock_rdlock(&myrwlock); 14 | 15 | std::cout << "read thread ID: " << pthread_self() << ", resourceID: " << resourceID << std::endl; 16 | 17 | //使用睡眠模拟读线程读的过程消耗了很久的时间 18 | sleep(1); 19 | 20 | pthread_rwlock_unlock(&myrwlock); 21 | } 22 | 23 | return NULL; 24 | } 25 | 26 | void* write_thread(void* param) 27 | { 28 | while (true) 29 | { 30 | //请求写锁 31 | pthread_rwlock_wrlock(&myrwlock); 32 | 33 | ++resourceID; 34 | std::cout << "write thread ID: " << pthread_self() << ", resourceID: " << resourceID << std::endl; 35 | 36 | //使用睡眠模拟读线程读的过程消耗了很久的时间 37 | sleep(1); 38 | 39 | pthread_rwlock_unlock(&myrwlock); 40 | } 41 | 42 | return NULL; 43 | } 44 | 45 | int main() 46 | { 47 | pthread_rwlockattr_t attr; 48 | pthread_rwlockattr_init(&attr); 49 | //设置成请求写锁优先 50 | pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); 51 | pthread_rwlock_init(&myrwlock, &attr); 52 | 53 | //创建5个请求读锁线程 54 | pthread_t readThreadID[5]; 55 | for (int i = 0; i < 5; ++i) 56 | { 57 | pthread_create(&readThreadID[i], NULL, read_thread, NULL); 58 | } 59 | 60 | //创建一个请求写锁线程 61 | pthread_t writeThreadID; 62 | pthread_create(&writeThreadID, NULL, write_thread, NULL); 63 | 64 | pthread_join(writeThreadID, NULL); 65 | 66 | for (int i = 0; i < 5; ++i) 67 | { 68 | pthread_join(readThreadID[i], NULL); 69 | } 70 | 71 | pthread_rwlock_destroy(&myrwlock); 72 | 73 | return 0; 74 | } -------------------------------------------------------------------------------- /rwlock3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int resourceID = 0; 6 | pthread_rwlock_t myrwlock; 7 | 8 | void* read_thread(void* param) 9 | { 10 | while (true) 11 | { 12 | //请求读锁 13 | pthread_rwlock_rdlock(&myrwlock); 14 | 15 | std::cout << "read thread ID: " << pthread_self() << ", resourceID: " << resourceID << std::endl; 16 | 17 | //使用睡眠模拟读线程读的过程消耗了很久的时间 18 | sleep(1); 19 | 20 | pthread_rwlock_unlock(&myrwlock); 21 | } 22 | 23 | return NULL; 24 | } 25 | 26 | void* write_thread(void* param) 27 | { 28 | while (true) 29 | { 30 | //请求写锁 31 | pthread_rwlock_wrlock(&myrwlock); 32 | 33 | ++resourceID; 34 | std::cout << "write thread ID: " << pthread_self() << ", resourceID: " << resourceID << std::endl; 35 | 36 | pthread_rwlock_unlock(&myrwlock); 37 | 38 | //放在这里增加请求读锁线程获得锁的几率 39 | sleep(1); 40 | } 41 | 42 | return NULL; 43 | } 44 | 45 | int main() 46 | { 47 | pthread_rwlockattr_t attr; 48 | pthread_rwlockattr_init(&attr); 49 | //设置成请求写锁优先 50 | pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); 51 | pthread_rwlock_init(&myrwlock, &attr); 52 | 53 | //创建5个请求读锁线程 54 | pthread_t readThreadID[5]; 55 | for (int i = 0; i < 5; ++i) 56 | { 57 | pthread_create(&readThreadID[i], NULL, read_thread, NULL); 58 | } 59 | 60 | //创建一个请求写锁线程 61 | pthread_t writeThreadID; 62 | pthread_create(&writeThreadID, NULL, write_thread, NULL); 63 | 64 | pthread_join(writeThreadID, NULL); 65 | 66 | for (int i = 0; i < 5; ++i) 67 | { 68 | pthread_join(readThreadID[i], NULL); 69 | } 70 | 71 | pthread_rwlock_destroy(&myrwlock); 72 | 73 | return 0; 74 | } -------------------------------------------------------------------------------- /semaphore.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class Task 9 | { 10 | public: 11 | Task(int taskID) 12 | { 13 | this->taskID = taskID; 14 | } 15 | 16 | void doTask() 17 | { 18 | std::cout << "handle a task, taskID: " << taskID << ", threadID: " << pthread_self() << std::endl; 19 | } 20 | 21 | private: 22 | int taskID; 23 | }; 24 | 25 | pthread_mutex_t mymutex; 26 | std::list tasks; 27 | sem_t mysemaphore; 28 | 29 | void* consumer_thread(void* param) 30 | { 31 | Task* pTask = NULL; 32 | while (true) 33 | { 34 | struct timespec ts; 35 | ts.tv_sec = 3; 36 | ts.tv_nsec = 0; 37 | 38 | if (sem_timewait(&mysemaphore, &ts) != 0) 39 | { 40 | if (errno == ETIMEOUT) 41 | { 42 | std::cout << "ETIMEOUT" << std::endl; 43 | } 44 | continue; 45 | } 46 | 47 | if (tasks.empty()) 48 | continue; 49 | 50 | pthread_mutex_lock(&mymutex); 51 | pTask = tasks.front(); 52 | tasks.pop_front(); 53 | pthread_mutex_unlock(&mymutex); 54 | 55 | pTask->doTask(); 56 | delete pTask; 57 | } 58 | 59 | return NULL; 60 | } 61 | 62 | void* producer_thread(void* param) 63 | { 64 | int taskID = 0; 65 | Task* pTask = NULL; 66 | 67 | while (true) 68 | { 69 | //pTask = new Task(taskID); 70 | 71 | pthread_mutex_lock(&mymutex); 72 | //tasks.push_back(pTask); 73 | //std::cout << "produce a task, taskID: " << taskID << ", threadID: " << pthread_self() << std::endl; 74 | 75 | pthread_mutex_unlock(&mymutex); 76 | 77 | //释放信号量,通知消费者线程 78 | sem_post(&mysemaphore); 79 | 80 | taskID ++; 81 | 82 | //休眠1秒 83 | sleep(1); 84 | } 85 | 86 | return NULL; 87 | } 88 | 89 | int main() 90 | { 91 | pthread_mutex_init(&mymutex, NULL); 92 | //初始信号量资源计数为0 93 | sem_init(&mysemaphore, 0, 0); 94 | 95 | //创建5个消费者线程 96 | pthread_t consumerThreadID[5]; 97 | for (int i = 0; i < 5; ++i) 98 | { 99 | pthread_create(&consumerThreadID[i], NULL, consumer_thread, NULL); 100 | } 101 | 102 | //创建一个生产者线程 103 | //pthread_t producerThreadID; 104 | //pthread_create(&producerThreadID, NULL, producer_thread, NULL); 105 | 106 | //pthread_join(producerThreadID, NULL); 107 | 108 | for (int i = 0; i < 5; ++i) 109 | { 110 | pthread_join(consumerThreadID[i], NULL); 111 | } 112 | 113 | sem_destroy(&mysemaphore); 114 | pthread_mutex_destroy(&mymutex); 115 | 116 | return 0; 117 | } -------------------------------------------------------------------------------- /semaphore_timewait.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class Task 9 | { 10 | public: 11 | Task(int taskID) 12 | { 13 | this->taskID = taskID; 14 | } 15 | 16 | void doTask() 17 | { 18 | std::cout << "handle a task, taskID: " << taskID << ", threadID: " << pthread_self() << std::endl; 19 | } 20 | 21 | private: 22 | int taskID; 23 | }; 24 | 25 | pthread_mutex_t mymutex; 26 | std::list tasks; 27 | sem_t mysemaphore; 28 | 29 | void* consumer_thread(void* param) 30 | { 31 | Task* pTask = NULL; 32 | while (true) 33 | { 34 | struct timespec ts; 35 | ts.tv_sec = 3; 36 | ts.tv_nsec = 0; 37 | 38 | if (sem_timewait(&mysemaphore, &ts) != 0) 39 | { 40 | if (errno == ETIMEDOUT) 41 | { 42 | std::cout << "ETIMEOUT" << std::endl; 43 | } 44 | continue; 45 | } 46 | 47 | if (tasks.empty()) 48 | continue; 49 | 50 | pthread_mutex_lock(&mymutex); 51 | pTask = tasks.front(); 52 | tasks.pop_front(); 53 | pthread_mutex_unlock(&mymutex); 54 | 55 | pTask->doTask(); 56 | delete pTask; 57 | } 58 | 59 | return NULL; 60 | } 61 | 62 | void* producer_thread(void* param) 63 | { 64 | int taskID = 0; 65 | Task* pTask = NULL; 66 | 67 | while (true) 68 | { 69 | //pTask = new Task(taskID); 70 | 71 | pthread_mutex_lock(&mymutex); 72 | //tasks.push_back(pTask); 73 | //std::cout << "produce a task, taskID: " << taskID << ", threadID: " << pthread_self() << std::endl; 74 | 75 | pthread_mutex_unlock(&mymutex); 76 | 77 | //释放信号量,通知消费者线程 78 | sem_post(&mysemaphore); 79 | 80 | taskID ++; 81 | 82 | //休眠1秒 83 | sleep(1); 84 | } 85 | 86 | return NULL; 87 | } 88 | 89 | int main() 90 | { 91 | pthread_mutex_init(&mymutex, NULL); 92 | //初始信号量资源计数为0 93 | sem_init(&mysemaphore, 0, 0); 94 | 95 | //创建5个消费者线程 96 | pthread_t consumerThreadID[5]; 97 | for (int i = 0; i < 5; ++i) 98 | { 99 | pthread_create(&consumerThreadID[i], NULL, consumer_thread, NULL); 100 | } 101 | 102 | //创建一个生产者线程 103 | //pthread_t producerThreadID; 104 | //pthread_create(&producerThreadID, NULL, producer_thread, NULL); 105 | 106 | //pthread_join(producerThreadID, NULL); 107 | 108 | for (int i = 0; i < 5; ++i) 109 | { 110 | pthread_join(consumerThreadID[i], NULL); 111 | } 112 | 113 | sem_destroy(&mysemaphore); 114 | pthread_mutex_destroy(&mymutex); 115 | 116 | return 0; 117 | } -------------------------------------------------------------------------------- /taskpoolmain.cpp: -------------------------------------------------------------------------------- 1 | #include "TaskPool.h" 2 | #include 3 | 4 | int main() 5 | { 6 | TaskPool threadPool; 7 | threadPool.init(); 8 | 9 | Task* task = NULL; 10 | for (int i = 0; i < 10; ++i) 11 | { 12 | task = new Task(); 13 | threadPool.addTask(task); 14 | } 15 | 16 | std::this_thread::sleep_for(std::chrono::seconds(5)); 17 | 18 | threadPool.stop(); 19 | 20 | return 0; 21 | } -------------------------------------------------------------------------------- /windowstls.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | __declspec(thread) int g_mydata = 1; 5 | 6 | DWORD __stdcall WorkerThreadProc1(LPVOID lpThreadParameter) 7 | { 8 | while (true) 9 | { 10 | ++g_mydata; 11 | //std::cout << "g_mydata = " << g_mydata << ", ThreadID = " << GetCurrentThreadId() << std::endl; 12 | Sleep(1000); 13 | } 14 | return 0; 15 | } 16 | 17 | DWORD __stdcall WorkerThreadProc2(LPVOID lpThreadParameter) 18 | { 19 | while (true) 20 | { 21 | std::cout << "g_mydata = " << g_mydata << ", ThreadID = " << GetCurrentThreadId() << std::endl; 22 | Sleep(1000); 23 | } 24 | return 0; 25 | } 26 | 27 | int main() 28 | { 29 | HANDLE hWorkerThreads[2]; 30 | hWorkerThreads[0] = CreateThread(NULL, 0, WorkerThreadProc1, NULL, 0, NULL); 31 | hWorkerThreads[1] = CreateThread(NULL, 0, WorkerThreadProc2, NULL, 0, NULL); 32 | 33 | CloseHandle(hWorkerThreads[0]); 34 | CloseHandle(hWorkerThreads[1]); 35 | 36 | while (true) 37 | { 38 | Sleep(1000); 39 | } 40 | 41 | return 0; 42 | } 43 | 44 | --------------------------------------------------------------------------------