├── 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 |
--------------------------------------------------------------------------------