- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章C++ 如何实现多线程与线程同步由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
先来创建一个简单的多线程实例,无参数传递版,运行实例会发现,主线程与子线程运行无规律.
#include <windows.h>#include <iostream>using namespace std;DWORD WINAPI Func(LPVOID lpParamter){ for (int x = 0; x < 10; x++) { cout << "thread function" << endl; Sleep(200); } return 0;}int main(int argc,char * argv[]){ HANDLE hThread = CreateThread(NULL, 0, Func, NULL, 0, NULL); CloseHandle(hThread); for (int x = 0; x < 10; x++) { cout << "main thread" << endl; Sleep(400); } system("pause"); return 0;}
。
这个方法与前面的CreateThread使用完全一致,只是在参数上面应使用void *该参数可以强转为任意类型,两者实现效果完全一致.
#include <windows.h>#include <iostream>#include <process.h>using namespace std;unsigned WINAPI Func(void *arg){ for (int x = 0; x < 10; x++) { cout << "thread function" << endl; Sleep(200); } return 0;}int main(int argc, char * argv[]){ HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, Func, NULL, 0, NULL); CloseHandle(hThread); for (int x = 0; x < 10; x++) { cout << "main thread" << endl; Sleep(400); } system("pause"); return 0;}
。
使用互斥锁可以实现单位时间内,只允许一个线程拥有对共享资源的独占,从而实现了互不冲突的线程同步.
#include <windows.h>#include <iostream>using namespace std;HANDLE hMutex = NULL; // 创建互斥锁// 线程函数DWORD WINAPI Func(LPVOID lpParamter){ for (int x = 0; x < 10; x++) { // 请求获得一个互斥锁 WaitForSingleObject(hMutex, INFINITE); cout << "thread func" << endl; // 释放互斥锁 ReleaseMutex(hMutex); } return 0;}int main(int argc,char * argv[]){ HANDLE hThread = CreateThread(NULL, 0, Func, NULL, 0, NULL); hMutex = CreateMutex(NULL, FALSE, "lyshark"); CloseHandle(hThread); for (int x = 0; x < 10; x++) { // 请求获得一个互斥锁 WaitForSingleObject(hMutex, INFINITE); cout << "main thread" << endl; // 释放互斥锁 ReleaseMutex(hMutex); } system("pause"); return 0;}
通过互斥锁,同步执行两个线程函数.
#include <windows.h>#include <iostream>using namespace std;HANDLE hMutex = NULL; // 创建互斥锁#define NUM_THREAD 50// 线程函数1DWORD WINAPI FuncA(LPVOID lpParamter){ for (int x = 0; x < 10; x++) { // 请求获得一个互斥锁 WaitForSingleObject(hMutex, INFINITE); cout << "this is thread func A" << endl; // 释放互斥锁 ReleaseMutex(hMutex); } return 0;}// 线程函数2DWORD WINAPI FuncB(LPVOID lpParamter){ for (int x = 0; x < 10; x++) { // 请求获得一个互斥锁 WaitForSingleObject(hMutex, INFINITE); cout << "this is thread func B" << endl; // 释放互斥锁 ReleaseMutex(hMutex); } return 0;}int main(int argc, char * argv[]){ // 用来存储线程函数的句柄 HANDLE tHandle[NUM_THREAD]; // /创建互斥量,此时为signaled状态 hMutex = CreateMutex(NULL, FALSE, "lyshark"); for (int x = 0; x < NUM_THREAD; x++) { if (x % 2) { tHandle[x] = CreateThread(NULL, 0, FuncA, NULL, 0, NULL); } else { tHandle[x] = CreateThread(NULL, 0, FuncB, NULL, 0, NULL); } } // 等待所有线程函数执行完毕 WaitForMultipleObjects(NUM_THREAD, tHandle, TRUE, INFINITE); // 销毁互斥对象 CloseHandle(hMutex); system("pause"); return 0;}
。
临界区与互斥锁差不多,临界区使用时会创建CRITICAL_SECTION临界区对象,同样相当于一把钥匙,线程函数执行结束自动上交,如下是临界区函数的定义原型.
//初始化函数原型VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);//销毁函数原型VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);//获取VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);//释放VOID LeaveCriticalSection( LPCRITICAL_SECTION lpCriticalSection);
这一次我们不适用互斥体,使用临界区实现线程同步,结果与互斥体完全一致,看个人喜好.
#include <windows.h>#include <iostream>using namespace std;CRITICAL_SECTION cs; // 全局定义临界区对象#define NUM_THREAD 50// 线程函数DWORD WINAPI FuncA(LPVOID lpParamter){ for (int x = 0; x < 10; x++) { //进入临界区 EnterCriticalSection(&cs); cout << "this is thread func A" << endl; //离开临界区 LeaveCriticalSection(&cs); } return 0;}int main(int argc, char * argv[]){ // 用来存储线程函数的句柄 HANDLE tHandle[NUM_THREAD]; //初始化临界区 InitializeCriticalSection(&cs); for (int x = 0; x < NUM_THREAD; x++) { tHandle[x] = CreateThread(NULL, 0, FuncA, NULL, 0, NULL); } // 等待所有线程函数执行完毕 WaitForMultipleObjects(NUM_THREAD, tHandle, TRUE, INFINITE); //释放临界区 DeleteCriticalSection(&cs); system("pause"); return 0;}
。
通过定义一个信号,初始化信号为0,利用信号量值为0时进入non-signaled状态,大于0时进入signaled状态的特性即可实现线程同步.
#include <windows.h>#include <iostream>using namespace std;static HANDLE SemaphoreOne;static HANDLE SemaphoreTwo;// 线程函数1DWORD WINAPI FuncA(LPVOID lpParamter){ for (int x = 0; x < 10; x++) { // 临界区开始时设置 signaled 状态 WaitForSingleObject(SemaphoreOne, INFINITE); cout << "this is thread func A" << endl; // 临界区结束则设置为 non-signaled 状态 ReleaseSemaphore(SemaphoreOne, 1, NULL); } return 0;}// 线程函数2DWORD WINAPI FuncB(LPVOID lpParamter){ for (int x = 0; x < 10; x++) { // 临界区开始时设置 signaled 状态 WaitForSingleObject(SemaphoreTwo, INFINITE); cout << "this is thread func B" << endl; // 临界区结束则设置为 non-signaled 状态 ReleaseSemaphore(SemaphoreTwo, 1, NULL); } return 0;}int main(int argc, char * argv[]){ // 用来存储线程函数的句柄 HANDLE hThreadA, hThreadB; // 创建信号量对象,并且设置为0进入non-signaled状态 SemaphoreOne = CreateSemaphore(NULL, 0, 1, NULL); // 创建信号量对象,并且设置为1进入signaled状态 SemaphoreTwo = CreateSemaphore(NULL, 1, 1, NULL); // 先执行这一个线程函数 hThreadA = CreateThread(NULL, 0, FuncA, NULL,0, NULL); hThreadB = CreateThread(NULL, 0, FuncB, NULL, 0, NULL); // 等待两个线程函数执行完毕 WaitForSingleObject(hThreadA, INFINITE); WaitForSingleObject(hThreadA, INFINITE); // 销毁两个线程函数 CloseHandle(SemaphoreOne); CloseHandle(SemaphoreTwo); system("pause"); return 0;}
上面的一段代码,容易产生死锁现象,即,线程函数B执行完成后,A函数一直处于等待状态.
执行WaitForSingleObject(semTwo, INFINITE);会让线程函数进入类似挂起的状态,当接到ReleaseSemaphore(semOne, 1, NULL);才会恢复执行.
#include <windows.h> #include <stdio.h> static HANDLE semOne,semTwo;static int num;// 线程函数A用于接收参书DWORD WINAPI ReadNumber(LPVOID lpParamter){ int i; for (i = 0; i < 5; i++) { fputs("Input Number: ", stdout); //临界区的开始 signaled状态 WaitForSingleObject(semTwo, INFINITE); scanf("%d", &num); //临界区的结束 non-signaled状态 ReleaseSemaphore(semOne, 1, NULL); } return 0;}// 线程函数B: 用户接受参数后完成计算DWORD WINAPI Check(LPVOID lpParamter){ int sum = 0, i; for (i = 0; i < 5; i++) { //临界区的开始 non-signaled状态 WaitForSingleObject(semOne, INFINITE); sum += num; //临界区的结束 signaled状态 ReleaseSemaphore(semTwo, 1, NULL); } printf("The Number IS: %d \n", sum); return 0;}int main(int argc, char *argv[]){ HANDLE hThread1, hThread2; //创建信号量对象,设置为0进入non-signaled状态 semOne = CreateSemaphore(NULL, 0, 1, NULL); //创建信号量对象,设置为1进入signaled状态 semTwo = CreateSemaphore(NULL, 1, 1, NULL); hThread1 = CreateThread(NULL, 0, ReadNumber, NULL, 0, NULL); hThread2 = CreateThread(NULL, 0, Check, NULL, 0, NULL); // 关闭临界区 WaitForSingleObject(hThread1, INFINITE); WaitForSingleObject(hThread2, INFINITE); CloseHandle(semOne); CloseHandle(semTwo); system("pause"); return 0;}
。
事件对象实现线程同步,与前面的临界区和互斥体有很大的不同,该方法下创建对象时,可以在自动non-signaled状态运行的auto-reset模式,当我们设置好我们需要的参数时,可以直接使用SetEvent(hEvent)设置事件状态,会自动执行线程函数.
#include <windows.h> #include <stdio.h> #include <process.h> #define STR_LEN 100 // 存储全局字符串static char str[STR_LEN];// 设置事件句柄static HANDLE hEvent;// 统计字符串中是否存在Aunsigned WINAPI NumberOfA(void *arg){ int cnt = 0; // 等待线程对象事件 WaitForSingleObject(hEvent, INFINITE); for (int i = 0; str[i] != 0; i++) { if (str[i] == 'A') cnt++; } printf("Num of A: %d \n", cnt); return 0;}// 统计字符串总长度unsigned WINAPI NumberOfOthers(void *arg){ int cnt = 0; // 等待线程对象事件 WaitForSingleObject(hEvent, INFINITE); for (int i = 0; str[i] != 0; i++) { if (str[i] != 'A') cnt++; } printf("Num of others: %d \n", cnt - 1); return 0;}int main(int argc, char *argv[]){ HANDLE hThread1, hThread2; // 以non-signaled创建manual-reset模式的事件对象 // 该对象创建后不会被立即执行,只有我们设置状态为Signaled时才会继续 hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); hThread1 = (HANDLE)_beginthreadex(NULL, 0, NumberOfA, NULL, 0, NULL); hThread2 = (HANDLE)_beginthreadex(NULL, 0, NumberOfOthers, NULL, 0, NULL); fputs("Input string: ", stdout); fgets(str, STR_LEN, stdin); // 字符串读入完毕后,将事件句柄改为signaled状态 SetEvent(hEvent); WaitForSingleObject(hThread1, INFINITE); WaitForSingleObject(hThread2, INFINITE); //non-signaled 如果不更改,对象继续停留在signaled ResetEvent(hEvent); CloseHandle(hEvent); system("pause"); return 0;}
。
线程函数中的定义中LPVOID允许传递一个参数,只需要在县城函数中接收并强转(int)(LPVOID)port即可.
#include <stdio.h>#include <Windows.h>// 线程函数接收一个参数DWORD WINAPI ScanThread(LPVOID port){ // 将参数强制转化为需要的类型 int Port = (int)(LPVOID)port; printf("[+] 端口: %5d \n", port); return 1;}int main(int argc, char* argv[]){ HANDLE handle; for (int port = 0; port < 100; port++) { handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ScanThread, (LPVOID)port, 0, 0); } WaitForSingleObject(handle, INFINITE); system("pause"); return 0;}
。
如果想在线程函数中传递多个参数,则需要传递一个结构指针,通过线程函数内部强转为结构类型后,取值,这个案例花费了我一些时间,网上也没找到合适的解决方法,或找到的都是歪瓜裂枣瞎转的东西,最后还是自己研究了一下写了一个没为题的.
其主要是线程函数中调用的参数会与下一个线程函数结构相冲突,解决的办法时在每次进入线程函数时,自己拷贝一份,每个人使用自己的那一份,才可以避免此类事件的发生,同时最好配合线程同步一起使用,如下时线程扫描器的部分代码片段.
#include <stdio.h>#include <windows.h>typedef struct _THREAD_PARAM{ char *HostAddr; // 扫描主机 DWORD dwStartPort; // 端口号}THREAD_PARAM;// 这个扫描线程函数DWORD WINAPI ScanThread(LPVOID lpParam){ // 拷贝传递来的扫描参数 THREAD_PARAM ScanParam = { 0 }; // 这一步很重要,如不拷贝,则会发生重复赋值现象,导致扫描端口一直都是一个。 // 坑死人的玩意,一开始我始终没有发现这个问题。sb玩意!! MoveMemory(&ScanParam, lpParam, sizeof(THREAD_PARAM)); printf("地址: %-16s --> 端口: %-5d 状态: [Open] \n", ScanParam.HostAddr, ScanParam.dwStartPort); return 0;}int main(int argc, char *argv[]){ THREAD_PARAM ThreadParam = { 0 }; ThreadParam.HostAddr = "192.168.1.10"; for (DWORD port = 1; port < 100; port++) { ThreadParam.dwStartPort = port; HANDLE hThread = CreateThread(NULL, 0, ScanThread, (LPVOID)&ThreadParam, 0, NULL); WaitForSingleObject(hThread, INFINITE); } system("pause"); return 0;}
文章出处:https://www.cnblogs.com/lyshark 。
以上就是C++ 如何实现多线程与线程同步的详细内容,更多关于C++ 实现多线程与线程同步的资料请关注我其它相关文章! 。
原文链接:https://www.cnblogs.com/LyShark/p/13664972.html 。
最后此篇关于C++ 如何实现多线程与线程同步的文章就讲到这里了,如果你想了解更多关于C++ 如何实现多线程与线程同步的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我将 Bootstrap 与 css 和 java 脚本结合使用。在不影响前端代码的情况下,我真的很难在css中绘制这个背景。在许多问题中,人们将宽度和高度设置为 0%。但是由于我的导航栏,我不能使用
我正在用 c 编写一个程序来读取文件的内容。代码如下: #include void main() { char line[90]; while(scanf("%79[^\
我想使用 javascript 获取矩阵数组的所有对 Angular 线。假设输入输出如下: input = [ [1,2,3], [4,5,6], [7,8,9], ] output =
可以用pdfmake绘制lines,circles和other shapes吗?如果是,是否有documentation或样本?我想用jsPDF替换pdfmake。 最佳答案 是的,有可能。 pdfm
我有一个小svg小部件,其目的是显示角度列表(参见图片)。 现在,角度是线元素,仅具有笔触,没有填充。但是现在我想使用一种“内部填充”颜色和一种“笔触/边框”颜色。我猜想line元素不能解决这个问题,
我正在为带有三角对象的 3D 场景编写一个非常基本的光线转换器,一切都工作正常,直到我决定尝试从场景原点 (0/0/0) 以外的点转换光线。 但是,当我将光线原点更改为 (0/1/0) 时,相交测试突
这个问题已经有答案了: Why do people write "#!/usr/bin/env python" on the first line of a Python script? (22 个回
如何使用大约 50 个星号 * 并使用 for 循环绘制一条水平线?当我尝试这样做时,结果是垂直(而不是水平)列出 50 个星号。 public void drawAstline() { f
这是一个让球以对角线方式下降的 UI,但球保持静止;线程似乎无法正常工作。你能告诉我如何让球移动吗? 请下载一个球并更改目录,以便程序可以找到您的球的分配位置。没有必要下载足球场,但如果您愿意,也可以
我在我的一个项目中使用 Jmeter 和 Ant,当我们生成报告时,它会在报告中显示 URL、#Samples、失败、成功率、平均时间、最短时间、最长时间。 我也想在报告中包含 90% 的时间线。 现
我有一个不寻常的问题,希望有人能帮助我。我想用 Canvas (android) 画一条 Swing 或波浪线,但我不知道该怎么做。它将成为蝌蚪的尾部,所以理想情况下我希望它的形状更像三角形,一端更大
这个问题已经有答案了: Checking Collision of Shapes with JavaFX (1 个回答) 已关闭 8 年前。 我正在使用 JavaFx 8 库。 我的任务很简单:我想检
如何按编号的百分比拆分文件。行数? 假设我想将我的文件分成 3 个部分(60%/20%/20% 部分),我可以手动执行此操作,-_-: $ wc -l brown.txt 57339 brown.tx
我正在努力实现这样的目标: 但这就是我设法做到的。 你能帮我实现预期的结果吗? 更新: 如果我删除 bootstrap.css 依赖项,问题就会消失。我怎样才能让它与 Bootstrap 一起工作?
我目前正在构建一个网站,但遇到了 transform: scale 的问题。我有一个按钮,当用户将鼠标悬停在它上面时,会发生两件事: 背景以对 Angular 线“扫过” 按钮标签颜色改变 按钮稍微变
我需要使用直线和仿射变换绘制大量数据点的图形(缩放图形以适合 View )。 目前,我正在使用 NSBezierPath,但我认为它效率很低(因为点在绘制之前被复制到贝塞尔路径)。通过将我的数据切割成
我正在使用基于 SVM 分类的 HOG 特征检测器。我可以成功提取车牌,但提取的车牌除了车牌号外还有一些不必要的像素/线。我的图像处理流程如下: 在灰度图像上应用 HOG 检测器 裁剪检测到的区域 调
我有以下图片: 我想填充它的轮廓(即我想在这张图片中填充线条)。 我尝试了形态学闭合,但使用大小为 3x3 的矩形内核和 10 迭代并没有填满整个边界。我还尝试了一个 21x21 内核和 1 迭代,但
我必须找到一种算法,可以找到两组数组之间的交集总数,而其中一个数组已排序。 举个例子,我们有这两个数组,我们向相应的数字画直线。 这两个数组为我们提供了总共 7 个交集。 有什么样的算法可以帮助我解决
简单地说 - 我想使用透视投影从近裁剪平面绘制一条射线/线到远裁剪平面。我有我认为是使用各种 OpenGL/图形编程指南中描述的方法通过单击鼠标生成的正确标准化的世界坐标。 我遇到的问题是我的光线似乎
我是一名优秀的程序员,十分优秀!