范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Windows线程同步的四种方式

  为什么要进行线程同步
  在多线程的程序中,很少有多个线程能在其生命期内进行完全独立的操作;通常情况是一些线程进行某些操作,而其他的线程必须对其操作后的结果进行了解。如果不采取同步机制,其他线程会在线程处理任务前访问处理结果,这样会产生错误的了解。例如,多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题;若一个线程负责写操作,其他线程负责读取操作,则不能保证读取的就是修改过的值,这时就必须在变量写操作过程时加上访问限制,在写操作完成后解除访问限制。这种保证线程能正确获取其他线程处理结束后的结果的措施称为线程同步。
  线程同步的四种方式:
  同步方式
  速度、资源开销
  跨进程
  资源统计
  Critical Section
  速度快、非内核对象
  不能用于不同进程
  不能资源统计(每次只能有一个线程对共享资源进行存取)
  Mutex
  速度慢,内核对象
  可用于不同进程
  不能资源统计
  Semaphore
  速度慢、内核对象
  可用于不同进程
  可资源统计(可以让一个或多个线程对共享资源进行存取)
  Event
  速度慢、内核对象
  可用于不同进程
  可资源统计 Critical Section
  临界区(Critical Section):通过对多线程的串行化来访问公共资源或一段代码,本身不是内核对象,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开。临界区被释放后,其他线程才可以抢占。
  【初始化临界区】VOID WINAPI InitializeCriticalSection(   LPCRITICAL_SECTION lpCriticalSection );
  【删除临界区】 VOID WINAPI DeleteCriticalSection(   LPCRITICAL_SECTION lpCriticalSection );
  【获取临界区】 VOID WINAPI EnterCriticalSection(   LPCRITICAL_SECTION lpCriticalSection );
  【释放临界区】 VOID WINAPI LeaveCriticalSection(   LPCRITICAL_SECTION lpCriticalSection );
  临界区在使用时,以CRITICAL_SECTION 结构对象保护共享资源,并分别用EnterCriticalSection() 和LeaveCriticalSection() 函数占有和释放一个临界区。所用到的CRITICAL_SECTION 结构对象必须经过InitializeCriticalSection() 的初始化后才能使用,而且必须确保所有线程中的任何试图访问此共享资源的代码都处在此临界区的保护之下。否则临界区将不会起到应有的作用,共享资源依然有被破坏的可能。
  【示例】 #include  #include  #include  #include  #include   int counter_value = 0;/*counter value*/ int max_counter = 5;/*counter value max*/ int min_counter = 0;/*counter value min*/ int producer_num = 0;/*生产者进入临界区次数*/ int consumer_num = 0;/*消费者进入临界区次数*/  CRITICAL_SECTION critical_section;/*临界区*/  DWORD WINAPI producer(LPVOID param) {   int* id = (int*)param;   while (true)   {     Sleep(rand() % 1000);     srand(counter_value);     EnterCriticalSection(&critical_section);     int add_count = rand() % 6 + 1;     /*判断是否超过最大值*/     if (counter_value < max_counter)     {       counter_value += add_count;       if (counter_value > max_counter)       {         add_count -= counter_value - max_counter;         counter_value = max_counter;       }       printf("Producer%d : produced %d items ", *id, add_count);     }     else     {       printf("Producer%d : counter value is full, cancel producing... ", *id);     }     printf("items num is %d ", counter_value);     LeaveCriticalSection(&critical_section);     //生产者进入临界区,次数增加     producer_num++;   } }  DWORD WINAPI consumer(LPVOID param) {   int* id = (int*)param;   while (true)    {     //sleep for a random period of time     Sleep(rand() % 1000);     EnterCriticalSection(&critical_section);     // generate      srand(counter_value);     int decrease_count = rand() % 6 + 1;     //判断是否超过最小值     if (counter_value > min_counter)      {       counter_value -= decrease_count;       if (counter_value <= min_counter)       {         decrease_count -= min_counter - counter_value;         counter_value = min_counter;       }       printf("Consumer%d : consumed %d items ", *id, decrease_count);     }     else     {       printf("Consumer%d : counter value is less than mixinum, cancel consuming... ", *id);     }     printf("items num is %d ", counter_value);     LeaveCriticalSection(&critical_section);     //消费者进入临界区,次数增加     consumer_num++;   }   return 0; }  int main() {   srand(counter_value);   int thread_producer = 5;   int thread_consumer = 5;   int pvalue[5] = { 0 };/*生产者*/   int cvalue[5] = { 0 };/*消费者*/   DWORD thread_pid[5], thread_cid[5];   HANDLE hthread_p[5], hthread_c[5];/*生产者和消费者线程*/   InitializeCriticalSection(&critical_section);   //FILE* fp;   //freopen_s(&fp, "CriticalSection_output.txt", "w", stdout);   /*create producer thread*/   for (int i = 0; i < thread_producer; ++i)   {     pvalue[i] = i + 1;     hthread_p[i] = CreateThread(NULL, 0, producer, &pvalue[i], 0, &thread_pid[i]);   }   /*create consumer thread*/   for (int i = 0; i < thread_consumer; ++i)   {     cvalue[i] = i + 1;     hthread_c[i] = CreateThread(NULL, 0, consumer, &cvalue[i], 0, &thread_cid[i]);   }   Sleep(1000);   for (int i = 0; i < thread_producer; ++i)   {     WaitForSingleObject(hthread_p[i], INFINITE);   }   for (int i = 0; i < thread_producer; ++i)   {     WaitForSingleObject(hthread_c[i], INFINITE);   }   DeleteCriticalSection(&critical_section);   //fclose(stdout);   return 0; }Mutex
  互斥量(Mutex):只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享。
  【创建互斥量】HANDLE WINAPI CreateMutex(   LPSECURITY_ATTRIBUTES lpMutexAttributes,// pointer to security attributes   BOOL bInitialOwner,  // flag for initial ownership   LPCTSTR lpName       // pointer to mutex-object name ); //参数意义: //lpMutextAttributes 传递安全相关的配置信息,使用默认安全设置时可以传递NULL //bInitialOwner 如果为TRUE,则创建出的互斥量对象属于调用该函数的线程,同时进入non-signaled状态; //如果为FALSE,则创建出的互斥量对象不属于任何线程,此时状态为signaled //lpName 用于命名互斥量对象。传入NULL时创建无名的互斥量对象
  【销毁互斥量】BOOL WINAPI CloseHandle(   HANDLE hObject );
  【获取互斥量】//获取函数  Windows线程创建中介绍的此函数,用于针对单个内核对象验证signaled。 DWORD WINAPI WaitForSingleObject(   HANDLE hHandle,        // handle to object to wait for    DWORD dwMilliseconds   // time-out interval in milliseconds   );
  【释放互斥量】BOOL WINAPI ReleaseMutex(     HANDLE hMutex  //需要释放的对象的句柄 );
  互斥量被某一线程获取时为 non-signaled 状态,释放时进入 signaled 状态。因此,可以利用 WaitForSingleObject 函数验证互斥量是否已分配。互斥量在 WaitForSingleObject 函数返回时自动进入 non-signaled 状态,因为它是" auto-reset "模式的内核对象。
  【示例】 #include  #include  #include  #include  #include   int counter_value = 0;/*counter value*/ int max_counter = 5;/*counter value max*/ int min_counter = 0;/*counter value min*/ int producer_num = 0;/*生产者进入临界区次数*/ int consumer_num = 0;/*消费者进入临界区次数*/  HANDLE Mutex = NULL;/*互斥锁*/  DWORD WINAPI producer(LPVOID param) {   int* id = (int*)param;   while (true)   {     Sleep(rand() % 1000);     srand(counter_value);     WaitForSingleObject(Mutex, INFINITE);     int add_count = rand() % 6 + 1;     /*判断是否超过最大值*/     if (counter_value < max_counter)     {       counter_value += add_count;       if (counter_value > max_counter)       {         add_count -= counter_value - max_counter;         counter_value = max_counter;       }       printf("Producer%d : produced %d items ", *id, add_count);     }     else     {       printf("Producer%d : counter value is full, cancel producing... ", *id);     }     printf("items num is %d ", counter_value);     ReleaseMutex(Mutex);     //生产者进入临界区,次数增加     producer_num++;   } }  DWORD WINAPI consumer(LPVOID param) {   int* id = (int*)param;   while (true)   {     //sleep for a random period of time     Sleep(rand() % 1000);     WaitForSingleObject(Mutex, INFINITE);     // generate      srand(counter_value);     int decrease_count = rand() % 6 + 1;     //判断是否超过最小值     if (counter_value > min_counter)     {       counter_value -= decrease_count;       if (counter_value <= min_counter)       {         decrease_count -= min_counter - counter_value;         counter_value = min_counter;       }       printf("Consumer%d : consumed %d items ", *id, decrease_count);     }     else     {       printf("Consumer%d : counter value is less than mixinum, cancel consuming... ", *id);     }     printf("items num is %d ", counter_value);     ReleaseMutex(Mutex);     //消费者进入临界区,次数增加     consumer_num++;   }   return 0; }  int main() {   srand(counter_value);   int thread_producer = 5;   int thread_consumer = 5;   int pvalue[5] = { 0 };/*生产者*/   int cvalue[5] = { 0 };/*消费者*/   DWORD thread_pid[5], thread_cid[5];   HANDLE hthread_p[5], hthread_c[5];/*生产者和消费者线程*/   Mutex = CreateMutex(NULL, FALSE, NULL);   //FILE* fp;   //freopen_s(&fp, "CriticalSection_output.txt", "w", stdout);   /*create producer thread*/   for (int i = 0; i < thread_producer; ++i)   {     pvalue[i] = i + 1;     hthread_p[i] = CreateThread(NULL, 0, producer, &pvalue[i], 0, &thread_pid[i]);   }   /*create consumer thread*/   for (int i = 0; i < thread_consumer; ++i)   {     cvalue[i] = i + 1;     hthread_c[i] = CreateThread(NULL, 0, consumer, &cvalue[i], 0, &thread_cid[i]);   }   Sleep(1000);   for (int i = 0; i < thread_producer; ++i)   {     WaitForSingleObject(hthread_p[i], INFINITE);   }   for (int i = 0; i < thread_producer; ++i)   {     WaitForSingleObject(hthread_c[i], INFINITE);   }   CloseHandle(Mutex);   //fclose(stdout);   return 0; }Semaphore
  信号量( Semaphore) 是维护0到指定最大值之间的同步对象。信号量状态在其计数大于0时是有信号,而其计数是0时是无信号的。信号量对象在控制上可以支持有限数量共享资源的访问。
  信号量的特点和用途可用下列几句话定义: 如果当前资源的数量大于0,则信号量有效; 如果当前资源数量是0,则信号量无效; 系统决不允许当前资源的数量为负值; 当前资源数量决不能大于最大资源数量。
  【创建信号量】 HANDLE WINAPI CreateSemaphore(   LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, //信号量的安全属性   LONG lInitialCount,//开始时可供使用的资源数   LONG lMaximumCount,//最大资源数   LPCWSTR lpName //信号量的名称 );
  【释放信号量】 BOOL WINAPI ReleaseSemaphore(   HANDLE hSemaphore, //要增加的信号量句柄   LONG lReleaseCount,//信号量的当前资源数增加lReleaseCount   LPLONG lpPreviousCount //增加前的数值返回 );
  【打开信号量】 HANDLE WINAPI OpenSemaphore(   DWORD dwDesiredAccess, //access   BOOL bInheritHandle,//如果允许子进程继承句柄,则设为TRUE   LPCWSTR lpName //指定要打开的对象的名字 );
  【销毁信号量】BOOL WINAPI CloseHandle(HANDLE hObject);
  【示例】 #include  #include  #include  #include  #include   int semaphore_num = 1; /*定义全局变量*/ HANDLE hSemaphore = NULL;/*定义信号量句柄*/  DWORD WINAPI ThreadFunction(LPVOID param) {   int* id = (int*)param;   long result = 0;   while (semaphore_num < 100)   {     WaitForSingleObject(hSemaphore, INFINITE);     printf("thread %d use semaphore_num: %d ", *id, semaphore_num);     ++semaphore_num;     ReleaseSemaphore(hSemaphore, 1, &result);     Sleep(1000);   }   return NULL; }  int main() {   HANDLE hThread[5] = { NULL };   int thread[5] = { 0 };   DWORD thread_id[5] = { 0 };   hSemaphore = CreateSemaphore(NULL, 1, 100, L"sema");   for (int i = 0; i < 5; ++i)   {     thread[i] = i + 1;     hThread[i] = CreateThread(NULL, 0, ThreadFunction, &thread[i], 0, &thread_id[i]);   }   Sleep(1000);   for (int i = 0; i < 5; ++i)   {     WaitForSingleObject(hThread[i], INFINITE);   }   CloseHandle(hSemaphore);   return 0; }Event
  事件(Event) :是WIN32提供的最灵活的线程间同步方式,事件可以处于激发状态(signaled or true)或未激发状态(unsignal or false)。根据状态变迁方式的不同,事件可分为两类: 手动设置:这种对象只可能用程序手动设置,在需要该事件或者事件发生时,采用SetEvent及ResetEvent来进行设置。 自动恢复:一旦事件发生并被处理后,自动恢复到没有事件状态,不需要再次设置。
  【创建事件】 HANDLE WINAPI CreateEvent(   LPSECURITY_ATTRIBUTES lpEventAttributes,   BOOL bManualReset,   BOOL bInitialState,   LPCWSTR lpName ); 参数说明: //lpEventAttributes  安全配置相关参数,采用默认安全配置时传入NULL   //bManualReset  传入TRUE时创建manual-reset模式的事件对象,传入FALSE时创建auto-reset模式的事件对象   //bInitialState  传入TRUE时创建signaled状态,传入FALSE时创建non-signaled状态的事件对象   //lpName  用于命名事件对象。传递NULL时创建无名的事件对象
  当第二个参数传入TRUE时将创建manual-reset模式的事件对象,此时即使WaitForSingleObject函数返回也不会回到non-signaled状态。因此,在这种情况下,需要通过如下2个函数明确更改对象状态。
  【打开事件】HANDLE WINAPI OpenEvent(   DWORD dwDesiredAccess,   BOOL bInheritHandle,   LPCSTR lpName );
  【复位事件】 BOOL WINAPI ResetEvent(HANDLE hEvent);
  【设置事件】 BOOL WINAPI SetEvent(HANDLE hEvent);
  传递事件对象句柄并希望改为non-signed状态时,应调用ResetEvent函数。如果希望改为signaled状态,则可以调用SetEvent函数。
  【示例】 #include  #include  #include  #include  #include   int event_num = 1; /*定义全局变量*/ HANDLE hEvent = NULL;/*定义事件句柄*/  DWORD WINAPI ThreadFunction(LPVOID param) {   int* id = (int*)param;   long result = 0;   while (event_num < 100)   {     WaitForSingleObject(hEvent, INFINITE);     printf("thread %d use semaphore_num: %d ", *id, event_num);     ++event_num;     SetEvent(hEvent);     Sleep(1000);   }   return NULL; }  int main() {   HANDLE hThread[5] = { NULL };   int thread[5] = { 0 };   DWORD thread_id[5] = { 0 };   hEvent = CreateEvent(NULL, FALSE, TRUE, L"event");   for (int i = 0; i < 5; ++i)   {     thread[i] = i + 1;     hThread[i] = CreateThread(NULL, 0, ThreadFunction, &thread[i], 0, &thread_id[i]);   }   Sleep(1000);   for (int i = 0; i < 5; ++i)   {     WaitForSingleObject(hThread[i], INFINITE);   }   CloseHandle(hEvent);   return 0; }

iPhone再次追赶安卓手机,苹果测试指纹识功能屏下指纹识别技术对于Android手机用户来说,跟吃饭一样平常。近日,有消息称苹果终于开始测试屏下指纹识别技术,并应用到iPhone中。在苹果官网发售中的iPhone系列中,拥有T画质体验全满贯!海信U79G系列电视即将上线不得不说海信电视一直是品牌朋友圈中玩得比较出位的一个,先放下在显示技术端不断深研的创新成果不表,在营销端,海信通过运动赛事合作成功在全球体育爱好者中树立了形态创新技术领先的品牌形象杜恩新品ProVisionSolo上手试玩折腾是开心,分享是快乐,大家好我是成都刘老烧,时隔一年我再次评测杜恩的产品,这次杜恩也紧跟芝杜的步伐升级为了Realtek1619DR可谓是铩羽而归,同时也能支持到12bit422iOS14怎么在桌面添加便签iOS系统是美国苹果公司所开发的手机操作系统,在使用iPhone系列手机的时候就可以体验到它,经过不断的迭代和系统升级,iOS系统已经更新至了iOS14版本。在iOS14系统的手机手机那些充电常识,你都知道吗?很多小伙伴儿都不知道,电池的健康会影响到手机的使用寿命。而现在智能手机都是使用不可拆卸式电池,导致我们很难自行更换电池,所以如何正确地使用以及保养就变得尤为重要了!一新手机第一次充亿级像素手机将销声匿迹,大底5000万一统江湖?8月18日,业内人士酸数码发文指出,超过一亿像素的主摄,接下来应该会在各家影像旗舰机销声匿迹了,大底5000万左右会一统江湖,亿像素反而变成了中低端机的参数修罗场。只看CMOS尺寸首发价8499元!联想全新拯救者R9000X明日开启预约CNMO新闻很多热爱电脑游戏的玩家对游戏本肯定不陌生,游戏本往往代表高性能,而联想拯救者游戏币在性能方面备受很多人认可。近日,联想拯救者发布消息表示,联想全新拯救者R9000X将于当SPen适配GalaxyZFold35G,会带来怎样的体验?哈喽,各位baby们,当你们听到三星GalaxyZFold35G也支持SPen功能之后,是不是也和公主一样激动呢?折叠屏也能实现SPen的画画写写啦不过,由于折叠屏的特殊性,想要适你认为手机上最鸡肋的功能是哪一个?嘿Siri我在明天早上七点叫醒我我已将你的闹钟起床设置到上午七点整手势操作逻辑没有安卓的方便顺手,后背敲击截屏的设置真的鸡肋。有时候很灵敏,随便敲哪里都能截屏。有时成功率不高,怎么用久了会变弯?苹果又有新窍门,新材料或打造史上最坚硬的iPad使用iPadPro的朋友应该知道,最近几年的iPadPro都有一个相似的毛病,那就是机身不太直,而根据苹果的介绍,iPadPro是塑料和金属两种材质拼装而成,生产完成冷却之后会有轻新机小米11T将发布苹果发布会定了传三星放弃自家处理器苹果下月将举行多场发布会据DigiTimes报道,知情人士透露,苹果计划在9月份举办多场产品发布会,而不是像去年那样,将秋季产品发布会分为9月10月和11月三个独立的活动。在今天发
中国无人机之王汪韬美国束手无策,让世界羡慕中国科技创新进入20世纪以来,随着中国自身实力的不断进步,和加入世贸组织之后对外交流的日益增多,中国也出现了一批参与到全球化竞争中的企业,例如腾讯阿里巴巴等,但是这些企业要么是布局广泛,要么是比特币被宣告死亡100多次,每次都王者归来,真的是靠炒作?币圈真的要完蛋了吗?这个问题每年都有小伙伴在问1。2011年比特币从1美元上涨至30美元仅用了4个月,同年6月份因为黑客攻击等安全问题比特币曾在两天内下跌68。2。之后比特币在20小米折叠屏新专利曝光,双打孔设计,背部神似三星ZFlip今年随着小米加入到折叠手机大军当中后,目前市面上可选的折叠手机品牌包括三星,华为,MOTO,柔宇和小米五家,后面VIVO和OPPO也都会推出折叠手机。要说折叠手机,销量最高,形态最小米12Ultra设计外观大改,背部设计超有辨识度,硬朗好看有质感笔歌科技独家报道小米12Ultra设计出样,外观大改,背部设计超有辨识度,硬朗好看有质感,背部去掉副屏,更加干净利落,一起来围观。01副屏之殇手机后背副屏的设计似乎很难打动消费的心Redmi的老对手回归,魅蓝即将重出江湖,红蓝大战再次上演?最近听到魅蓝手机要重出江湖的消息,作为一名老煤油平静如水的内心倒是泛起一丝波澜。如果那时候魅蓝没有断掉,估计曾经的红蓝大战还将持续,作战的双方指的就是极具性价比的Redmi和青年良握在手里的超跑,雷柏VT960游戏鼠标,科技感爆表前言对于我们这种对竞技游戏一直保持热爱的小伙伴来说,除了游戏本身,还感兴趣的可能就是电竞外设了。尤其是鼠标,鼠标的好坏,习惯与不习惯,相比其它外设来说,对于游戏而言是影响最大的。随Win11现身蓝牙认证库,另外电脑可以直升Win11?说到Windows11,那可真是六月底到现在被用户各种争议讨论啊!众所周知,微软带来的Win11更新是十分令人期待的,毕竟时隔多年,一套全新的操作系统应该会是不一般的体验。然而,据iOS14。7beta5了,正式版即将发布苹果向开发者推送了iOSiPadOS14。7的第5个开发者测试版,距离上一个开发者测试版推送刚过一周。iOS14。7beta5更新截图本次更新版本号为18G5063a,从iOS14荣耀50系列高频PWM调光功能解析眼睛看不见的调光,才是好的调光上次科普了荣耀50Pro的单电芯双回路100W快充方案后,后台陆续收到了很多关于荣耀50系列功能性的问题咨询,如一站式Vlog视频拍摄是怎么实现的?其盘点那些续航能力非常好的挂脖式蓝牙耳机,挂脖式蓝牙耳机推荐我们又见面啦,今天我来给大家又又又又推荐新挂脖式蓝牙耳机啦。是不是上一次推荐的时候许多人看的不是很仔细,没关系的,今天我又来给大家推荐了。今天推荐的是那些续航能力超强,音质不错,外最适合跑步运动的无线蓝牙耳机,HAKIIACTION哈氪觉醒体验转眼到了盛夏,每天走两步就满头大汗,更何况是跑步,每次跑步运动5公里下来,身上的衣服都会被汗湿,热的满头大汗,睁不开眼睛,在跑步时,我喜欢一边听歌,一边跑步,那样可以减少跑步带来的