C++拾遗--多线程:主线程与子线程的同步

C++拾遗--多线程:主线程与子线程的同步

前言

在多线程编程时,有时是需要要求主线程与子线程同步的。

正文

程序演示

下面的一个例子,演示了主线程与子线程之间的同步问题。

程序描述:

在主线程中,有一整型变量count,初始化为0。主线程把count的地址传递给开启的子线程,子线程打印获取的值,随后主线程递增count的值,再次开启另一个子线程,传递count的地址……

#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <Windows.h>
#define Thread_NUM 20
void thread_go(void *p)
{
	Sleep(100);     //do some work
	int i = *(int*)p;
	Sleep(100);     //do some work
	printf("线程%d,报数%d\n", GetCurrentThreadId(), i);
}
int main(void)
{
	printf("******主线程与子线程的同步问题演示***by David***\n");
	HANDLE handles[Thread_NUM];
	int count = 0;
	for (int i = 0; i < Thread_NUM; i++)
	{
		handles[i] = _beginthread(thread_go, 0, &count);
		Sleep(100);     //do some work
		WaitForSingleObject(handles[i], INFINITE);   //开启这行代码也可实现主线程与子线程同步
		count++;     //在子线程获取这个值之前,主线程很可能对它进行了修改,从而某次报数被跳过。
	}
	//永久等待所有子线程结束
	WaitForMultipleObjects(Thread_NUM, handles, TRUE, INFINITE);
	getchar();
	return 0;
}

运行

这个运行结果是特地挑选的,因为它暴露了所有的问题:

  1. 理论上报数结果是从0连续到19。可运行结果中有的数被跳过了,如1,15。
  2. 有的数被重复报数,如14,16。
  3. 为何会出现20?这本不应该。

问题分析

针对这三个问题详细分析出现的原因:

问题一

有的数被跳过。这在代码的count++;这句后有详细解释。看下代码注释即可明白。

问题二

有的数被重复。这个原因也和上一个问题原因一样:上一个线程在获取count值之前,count的值就被主线程改了,从而当上一个线程获取count的值时,极有可能它获取的值大小和下一个子线程获取的是同一个值。于是重复了。

问题三

原因很多,其中一个可以是:最后i和count的大小都是20,循环本应结束,主线程却被打断。若某子线程若还未保存count的值,子线程保存的就是count最后的值20。

后续文章,通过相应方法,实现主子线程同步。

本专栏目录

所有内容的目录

时间: 2024-08-04 02:35:50

C++拾遗--多线程:主线程与子线程的同步的相关文章

python多线程(等待)主线程和子线程的同步执行

#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import time def fun(name, ls_name, front_thread = None): ''' 线程启动函数 通过front_thread来使用线程有序的运行 ''' time.clock() time.sleep(2) # 如果front_thread存在,则在front_thread运行完成后,才运行当前线程 if front_thread

C#主线程等待子线程运行结束

佐左佑右 原文 C#主线程等待子线程运行结束 由于主程序中调用matlab的dll文件进行计算要用较长的时间,主界面会有很长时间的卡顿,造成的用户感受十分不好,因此我想在调用时,将调用放入子线程中,然后在主线程中弹出一个提示框,显示数据正在加载,等子线程运行结束后,主线程继续工作. 使用的是http://hi.baidu.com/oktell/item/5527f51d93abb4a5feded5a8中所提到的方法,用了这篇文章中的第一个方式,即不带参数的. 之后在其中加入了显示和关闭提示框的代

Java并发编程原理与实战六:主线程等待子线程解决方案

本文将研究的是主线程等待所有子线程执行完成之后再继续往下执行的解决方案 public class TestThread extends Thread { public void run() { System.out.println(this.getName() + "子线程开始"); try { // 子线程休眠五秒 Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.

C++拾遗--多线程:临界区解决子线程的互斥

C++拾遗--多线程:临界区解决子线程的互斥 前言 为了解决子线程的互斥问题,windows系统提出了关键段或临界区(CRITICAL_SECTION)的概念.它一共有四个共两对操作:初始化.销毁,进入.离开.它们定义在头文件synchapi.h中. 1.初始化变量 VOID WINAPI InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); 2.销毁变量 VOID WINAPI DeleteCriticalSect

Java实现主线程等待子线程

本文介绍两种主线程等待子线程的实现方式,以5个子线程来说明: 1.使用Thread的join()方法,join()方法会阻塞主线程继续向下执行. 2.使用Java.util.concurrent中的CountDownLatch,是一个倒数计数器.初始化时先设置一个倒数计数初始值,每调用一次countDown()方法,倒数值减一,他的await()方法会阻塞当前进程,直到倒数至0. join方式代码如下: [java] view plain copy package com.test.thread

Android 使用handler实现线程间发送消息 (主线程 与 子线程之间)、(子线程 与 子线程之间)

keyword:Android 使用handler实现线程间发送消息 (主线程 与 子线程之间).(子线程 与 子线程之间) 相信大家平时都有使用到异步线程往主线程(UI线程)发送消息的情况. 本文主要研究Handler的消息发送. 包含主线程往子线程发送消息,子线程之间互相发送消息. 一.主线程向子线程发送消息. 实现过程比較简单: 主线程发送消息到异步线程.异步线程接收到消息后在再发送一条消息给主线程. 1. 初始化主线程的Handler,用来接收子线程的消息. 2. 启动异步线程.在异步线

Android主线程、子线程通信(Thread+handler)

Android是基于Java的,所以也分主线程,子线程! 主线程:实现业务逻辑.UI绘制更新.各子线程串连,类似于将军: 子线程:完成耗时(联网取数据.SD卡数据加载.后台长时间运行)操作,类似于小兵: 一.子线程向主线程发消息(Thread+handler): 1.主线程中定义Handler: Java代码   Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.h

第一章、主线程与子线程

第一章.主线程与子线程 但我们打开FBReader程序的一刻,代码会立即创建一个子线程.之后,主线程会负责在屏幕上显示一个进度条,而子线程则在后台开始读取epub文件. PS:进度条的样子如下图所示,不过由于加载速度很快,这进度条都是一闪而过的.这张图片是在单步调试的环境下截取的. 在这一章,我们将详细介绍,程序如何创建子线程,以及如何控制进度条的显示与消失. 本章涉及的核心类是UIUtil类. FBReader默认首先进入的FBReader类,这是在AndroidManifes.xml设定的.

(转)C#/.NET主线程与子线程之间的关系

一般 一个应用程序就对应一个进程,一个进程可有一个或多个线程,而一般有一个主线程. 有的博客上说“至少一个主线程”,这一说法持有怀疑         主线程与子线程之间的关系         **默认情况,在新开启一个子线程的时候,他是前台线程,只有,将线程的IsBackground属性设为true;他才是后台线程         *当子线程是前台线程,则主线程结束并不影响其他线程的执行,只有所有前台线程都结束,程序结束         *当子线程是后台线程,则主线程的结束,会导致子线程的强迫结