精华内容
下载资源
问答
  • C#多线程互斥实例 多线程获取同一变量(不重复)。是一个很好的学习例子
  • 多线程访问同一变量是否需要加锁

    千次阅读 2015-09-08 21:49:06
    对于多线程访问同一变量是否需要加锁的问题,先前大家都讨论过。今天用代码验证了一下之前的猜想:32位CPU与内存的最小交换数据为4字节/次,这也是结构体要对齐4字节的原因。在物理上,CPU对于同一4字节的内存单元,...
    对于多线程访问同一变量是否需要加锁的问题,先前大家都讨论过。今天用代码验证了一下之前的猜想:32位CPU与内存的最小交换数据为4字节/次,这也是结构体要对齐4字节的原因。在物理上,CPU对于同一4字节的内存单元,不可能写2个字节的同时,又读了3字节。
    

    测试环境为:

    XEON 2CPU*2
    Windows7

    采用50,50,50线程交叉读写,试验代码如下:
    C/C++ code
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    int  g_test;
    int  temp;
    BOOL  g_bRunning;
    DWORD  WINAPI thWriteProc1( LPVOID  lParam)
    {
         while (g_bRunning)
         {
             g_test = 12345678;
             Sleep(1);
         }
         return  0;
    }
    DWORD  WINAPI thWriteProc2( LPVOID  lParam)
    {
         while (g_bRunning)
         {
             g_test = 13579246;
             Sleep(1);
         }
         return  0;
    }
     
    DWORD  WINAPI thReadProc( LPVOID  lParam)
    {
         while (g_bRunning)
         {
             temp = g_test; //读取值
             if  ( temp != 12345678 && temp != 13579246 )
             {
                 g_bRunning = FALSE;
                 CString str;
                 str.Format( "read error!%d" , temp);
                 AfxMessageBox(str);
                 break ;
             }
             Sleep(1);
         }
         return  0;
    }
    void  CTestMultiyAccessIntDlg::OnButton1() 
    {
         g_bRunning = TRUE;
         for  int  i = 0; i < 50; i++ )
         {
             //创建50个写线程1
             CreateThread( NULL, 0, thWriteProc1, NULL, 0, NULL );
         }
         for  int  i = 0; i < 50; i++ )
         {
             //创建50个写线程2
             CreateThread( NULL, 0, thWriteProc2, NULL, 0, NULL );
         }
         for  int  i = 0; i < 50; i++ )
         {
             //创建50个读线程
             CreateThread( NULL, 0, thReadProc, NULL, 0, NULL );
         }
    }


    测试方法:
    改变g_test的类型,给g_test赋予不同的值(不要超过类型的上限值)

    测试现象:
    当g_test为int,short char时,不存在多线程交叉读写错误的问题
    当g_test为double, float, __int64时,存在多线程交叉读写错误的问题,对于__int64,当赋值小于0xFFFFFFFF时不出错,当大于0xFFFFFFFF时出错
    当g_test为CString时,存在交叉读写错误,有时候程序崩溃
    另:不加Sleep(1)机器卡死过,CPU占用率达到100%,4个核心占用率全满,可以保证运行在多核环境下

    现象分析:
    (1)int short char均为小于4字节的连续内存块,CPU一条指令就可以读写它们的值,CPU不可能同一个时间执行两条指令
    (2)double为8字节,如果写线程先写了4字节,读线程读了8字节,这自然导致数据被破坏
    (3)float也为4字节,我也不是太清楚为什么不行,可能是VC对浮点数的处理比较特殊有关,浮点数具有复杂内存结构
    (4)__int64为8字节,存在和(2)相同的情况,如果__int64小于等于0xFFFFFFFF,相当于只改变了低4字节,因此就没有问题
    (5)CString为类类型,具有复杂结构,显然不行

    结论:
    1.对于int,short,char,BOOL等小于等于4字节的简单数据类型,如果无逻辑上的先后关系,多线程读写可以完全不用加锁
    2.尽管float为4字节,多线程访问时也需要加锁
    3.对于大于4字节的简单类型,比如double,__int64等,多线程读写必须加锁。
    4.对于所有复杂类型,比如类,结构体,容器等类型必须加锁

    尽管对int等类型的多线程读写不需要加锁,但是逻辑上有必要加锁的还是应该加锁
    例如:对于一个多线程访问的全局变量int g_test
    int count = g_test/1024;
    int mod = g_test%1024;
    由于是两条语句,执行完第一条之后,别的线程很可能已经修改了g_test的值,如果希望这两条语句执行时,g_test不发生变化,就必须加锁,以保证两条语句执行的整体性。
    Lock();
    int count = g_test/1024;
    int mod= g_test%1024;
    UnLock();
    如果不加锁,也可以改为先保存到一个临时变量里
    int temp = g_test;
    int count = temp/1024;
    int mod = temp%1024;
    展开全文
  • 对于多线程访问同一变量是否需要加锁的问题,先前大家都讨论过。今天用代码验证了一下之前的猜想:32位CPU与内存的最小交换数据为4字节/次,这也是结构体要对齐4字节的原因。在物理上,CPU对于同一4字节的内存单元,...
    对于多线程访问同一变量是否需要加锁的问题,先前大家都讨论过。今天用代码验证了一下之前的猜想:32位CPU与内存的最小交换数据为4字节/次,这也是结构体要对齐4字节的原因。在物理上,CPU对于同一4字节的内存单元,不可能写2个字节的同时,又读了3字节。
    

    测试环境为:

    XEON 2CPU*2
    Windows7

    采用50,50,50线程交叉读写,试验代码如下:
    C/C++ code
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    int  g_test;
    int  temp;
    BOOL  g_bRunning;
    DWORD  WINAPI thWriteProc1( LPVOID  lParam)
    {
         while (g_bRunning)
         {
             g_test = 12345678;
             Sleep(1);
         }
         return  0;
    }
    DWORD  WINAPI thWriteProc2( LPVOID  lParam)
    {
         while (g_bRunning)
         {
             g_test = 13579246;
             Sleep(1);
         }
         return  0;
    }
     
    DWORD  WINAPI thReadProc( LPVOID  lParam)
    {
         while (g_bRunning)
         {
             temp = g_test; //读取值
             if  ( temp != 12345678 && temp != 13579246 )
             {
                 g_bRunning = FALSE;
                 CString str;
                 str.Format( "read error!%d" , temp);
                 AfxMessageBox(str);
                 break ;
             }
             Sleep(1);
         }
         return  0;
    }
    void  CTestMultiyAccessIntDlg::OnButton1() 
    {
         g_bRunning = TRUE;
         for  int  i = 0; i < 50; i++ )
         {
             //创建50个写线程1
             CreateThread( NULL, 0, thWriteProc1, NULL, 0, NULL );
         }
         for  int  i = 0; i < 50; i++ )
         {
             //创建50个写线程2
             CreateThread( NULL, 0, thWriteProc2, NULL, 0, NULL );
         }
         for  int  i = 0; i < 50; i++ )
         {
             //创建50个读线程
             CreateThread( NULL, 0, thReadProc, NULL, 0, NULL );
         }
    }


    测试方法:
    改变g_test的类型,给g_test赋予不同的值(不要超过类型的上限值)

    测试现象:
    当g_test为int,short char时,不存在多线程交叉读写错误的问题
    当g_test为double, float, __int64时,存在多线程交叉读写错误的问题,对于__int64,当赋值小于0xFFFFFFFF时不出错,当大于0xFFFFFFFF时出错
    当g_test为CString时,存在交叉读写错误,有时候程序崩溃
    另:不加Sleep(1)机器卡死过,CPU占用率达到100%,4个核心占用率全满,可以保证运行在多核环境下

    现象分析:
    (1)int short char均为小于4字节的连续内存块,CPU一条指令就可以读写它们的值,CPU不可能同一个时间执行两条指令
    (2)double为8字节,如果写线程先写了4字节,读线程读了8字节,这自然导致数据被破坏
    (3)float也为4字节,我也不是太清楚为什么不行,可能是VC对浮点数的处理比较特殊有关,浮点数具有复杂内存结构
    (4)__int64为8字节,存在和(2)相同的情况,如果__int64小于等于0xFFFFFFFF,相当于只改变了低4字节,因此就没有问题
    (5)CString为类类型,具有复杂结构,显然不行

    结论:
    1.对于int,short,char,BOOL等小于等于4字节的简单数据类型,如果无逻辑上的先后关系,多线程读写可以完全不用加锁
    2.尽管float为4字节,多线程访问时也需要加锁
    3.对于大于4字节的简单类型,比如double,__int64等,多线程读写必须加锁。
    4.对于所有复杂类型,比如类,结构体,容器等类型必须加锁

    尽管对int等类型的多线程读写不需要加锁,但是逻辑上有必要加锁的还是应该加锁
    例如:对于一个多线程访问的全局变量int g_test
    int count = g_test/1024;
    int mod = g_test%1024;
    由于是两条语句,执行完第一条之后,别的线程很可能已经修改了g_test的值,如果希望这两条语句执行时,g_test不发生变化,就必须加锁,以保证两条语句执行的整体性。
    Lock();
    int count = g_test/1024;
    int mod= g_test%1024;
    UnLock();
    如果不加锁,也可以改为先保存到一个临时变量里
    int temp = g_test;
    int count = temp/1024;
    int mod = temp%1024;
    展开全文
  • 在Java中,如果启动线程对同一个对象或者变量时候,在没有安全保护前提下有可能会抛出并异常 java.util.ConcurrentModificationException 当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常(并发...

    在Java中,如果启动多个线程对同一个对象或者变量时候,在没有安全保护前提下有可能会抛出并异常

    java.util.ConcurrentModificationException

    当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常(并发异常)

    解决方法:

    • 在对象/变量前加上volatile。Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。而volatile关键字就是提示JVM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。由于使用volatile屏蔽掉了JVM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字
    • 将对象/变量加上锁synchronized修饰。在线程中,使用同步方法或者同步块。
    • 使用带有线程安全的线程。如:继承TimerTask类实现线程,用Timer.schedule启动线程 。

    转载于:https://www.cnblogs.com/DreamRecorder/p/9257603.html

    展开全文
  • 很简单的逻辑,就是for循环开新的线程然后每个线程执行对static静态变量count的修改。 在inc()方法中,对count用for循环执行操作很重要。因为现在的电脑性能都应经很好(一般情况下资源都浪费了),所以如果简单...

    先贴代码:

    import java.util.Vector;
    
    public class Counter {
    
    	public static int count = 0;
    //	synchronized 
    	public static void inc() {
    		for (int i = 0; i < 1000; i++){
    			count++;
    		}
    		System.out.println(Thread.currentThread().getName() + "----" + count);
    	}
    
    	public static void main(String[] args) {
    		Vector<Thread> ts = new Vector<Thread>();
    		for (int i = 0; i < 200; i++) {
    			Thread t = new Thread(new Runnable() {
    				@Override
    				public void run() {
    					Counter.inc();
    				}
    			});
    			ts.add(t);
    			t.start();
    		}
    		for (Thread t : ts) {
    			try {
    				t.join();
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    		
    		System.out.println("----------" + Counter.count);
    	}
    }

    很简单的逻辑,就是for循环开新的线程然后每个线程执行对static静态变量count的修改。

    在inc()方法中,对count用for循环执行操作很重要。因为现在的电脑性能都应经很好(一般情况下资源都浪费了),所以如果简单地执行一次count++的话,又没有一些线程和它竞争CPU,所以很有可能看不到实验的结果。(我的机器就是这种情况,找我们项目组的哥问了才了解)。

    线上一张图,然后再说:(图片来自:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html)<----他的这篇文章有问题,可以说代码根本和他说的对不上,下面再喷他,但是他的分析是对的。


    我们的用循环新开的线程肯定不是主线程。所以我们的子线程要去访问count变量,就是这样,read -> load -> use -> assign -> store -> write.

    read 和load一下子就OK了,但是use,assign,store是对自己现成的这块内存的操作,是可以进行很多次和需要时间的。

    那么问题容易出现在什么地方呢,就出在这块时间上,世界并不是静止的,计算机也一样。你操作的这段时间,其他的进程也可以操作(因为你并没有加锁同步)。街上的美女又不是只有你可以看,对不对。

    好了,这就是问题所在。执行这段代码的时候一个线程拿到了主线程内存中的count的拷贝,然后要进行1000次加操作。可是1000次还没干完呢,又来了个线程得到了最新的count的拷贝,也进行1000加操作。但是第二个进程得到的拷贝并不是1000,可能只有209.好了,解释到这里就可以了。

    然后最后打印出最后的count的值,验证代码。

    开始喷(轻喷)。上图的作者的代码里面,没有:

    for (Thread t : ts) {
    			try {
    				t.join();
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}

    这段代码,然后就输出,就说怎么地怎么地。问什么不对很简单,这段代码的作用是让主进程在所有子进程执行完之后执行。如果子进程没执行完就把半路上的count输出,效果虽然跟没同步是一样的但是绝不是那么回事。

    关于让主进程在子进程之后执行的方法主要有两个,以后再说。哦,对了,join()的意思是:“等待该线程执行完之后再执行”,将主语和宾语带入,就是:“等待我子线程执行完之后你主线程再执行”。

    (如果把join用在产生新线程的for循环中的话你会发现线程ID都是排的整整齐齐的呢。。。。为什么应该不难理解)

    接下来想想,同步的话怎么搞呢?

    synchrinized放在public和static之间就好(这么详细我也醉了)。然后运行一下看看,你就懂了。

    展开全文
  • 文章目录示例CPU的内存模型Java...那么问题来了:多线程调用access()方法时,接口访问次数统计的结果是否能保证准确呢? 显而易见:不能。 CPU的内存模型 接下来分析一下为什么上面统计的结果会有问题. 我们先来简单理
  • 程序中通常将多线程同时访问的某个资源作为临界区,需要定义一个CRITICAL_SECTION类型的变量,然后调用InitializeCriticalSection函数对变量进行初始化; 函数声明: VOID InitializeCriticalSection(LPCRITICAL_...
  • ssm框架下多线程操作同一对象

    千次阅读 2018-01-19 18:37:59
    前几天遇到这样一个问题,在ssm框架下如何让个人对同一篇文章的同一个段落排队进行编辑,排队很容易就想到java中的queue队列,经过查阅才知道只要是框架它都会自动给你处理线程问题,每一个用户是一个线程,当用户...
  • 多线程执行同一方法问题

    千次阅读 2018-04-09 12:36:36
    前言当线程启动,访问一个实例中的一个方法时,执行情况如何,是等待一个线程执行完成还是同时处理?数据又该如何处理?Java虚拟机运行时数据区的组成由五个部分组成,分别是:方法区,堆,栈,本地方法栈,程序...
  • C++多线程同时读同一文件

    千次阅读 2020-04-06 11:25:32
    C++多线程同时读同一文件 #include <thread> #include <iostream> #include <fstream> #include <string> #include <sstream> #include <vector> #include <chrono> ...
  • 多线程是否可以同时读取同一内存变量多线程是否可以同时读取同一内存变量?只是对他进行读取不进行写入修改 那么在多线程中是否会因此而出错? itljl 2012-12-23 00:14 读可以,修改不可以。 ...
  • 如何让多线程同一时刻并发执行

    千次阅读 2019-10-29 10:35:26
    多线程同一时刻并发执行 代码使用场景:需要在本机试试自己的接口在某个时间访问可以被执行的频率【严格意义上来说,不算同一时刻,因为多线程执行也是上下文切换的】 其实你想找的是某个时间范围(如一秒内),你...
  • Java多线程操作局部变量与全局变量

    万次阅读 2013-10-18 10:30:04
    在这篇文章里,我们首先阐述什么是同步,不同步有什么问题,然后讨论可以采取哪些措施控制... 说到线程同步,大部分情况下, 我们是在针对“单对象多线程”的情况进行讨论,一般会将其分成两部分,一部分是关于“共享
  • 【线程】多线程同时拷贝同一文件

    千次阅读 2017-08-14 19:25:42
    高效率的多线程拷贝
  • 多线程共享一块内存区域,但是对这块共享区域加锁访问。对调用static变量的方法使用lock或synchronized 《深入理解java虚拟机》知识点 程序运行的时候,内存主要由以下部分组成: 堆: 所有线程共享一...
  • 1,加同步锁采用syschronized 关键字到对应的方法或者方法代码块,线程在同一个时刻其实只有一个线程可以访问到共享资源(类似单线程) 2.引入ThreadLocal , 在每个线程中建立一个对应的变量的副本, ...
  • Java多线程之对象及变量的并发访问

    千次阅读 2018-08-06 19:22:51
    synchronized 同步方法 方法内的变量为线程安全,实例变量非线程安全。调用关键字synchronized声明...对于多线程访问同一对象,哪个对象先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁Lock,...
  • 关键字synchronized可以保证在同一时刻,只有一个线程可以执行某一个方法,或者某一个代码块。 同步并不是单单指线程之间的互斥。如果没有同步,一个线程的变化就不能被其他线程看到。同步不仅可以阻止一个线程看到...
  • 1.Qt下,多线程使用互斥锁安全访问同一全局变量;2.源码中定义了ThreadA和ThreadB,定义变量后,依次调用函数start()来启动重写的run()函数
  • 假设现在有线程A和线程B,还有全局变量i,寄存器X 1、线程对全局变量的访问时分三步走的 : (1)取全局变量i到某个寄存器X ...2、多线程实际上是由时间片选来轮换进行的。当线程A执行到某个地方还没结束的...
  • 对于多线程访问同一变量是否需要加锁的问题,先前大家都讨论过。今天用代码验证了一下之前的猜想:32位CPU与内存的最小交换数据为4字节/次,这也是结构体要对齐4字节的原因。在物理上,CPU对于同一4字节的内存单元,...
  • 多线程同时操作全局变量的出错演示:演示了9个线程同时操作全局变量的出错结果,并采用自动验证结果,直到程序出错,有很好的演示和学习价值。
  • 建立线程加快速度,但是如GloBestResult=1, 线程a和b计算的result分别为2和3匀大于GloBestResult,而b线先改动GloBestReult 然后轮到线程a,那3这个结果就被覆盖了。 怎么解决,加入信号量吗?会不会杀鸡用宰...
  • Android 多线程变量同步的问题

    千次阅读 2016-06-06 20:27:58
    概述在 Android 开发中,常常会遇到这样的需求:主线程用到的成员变量需要在子线程初始化,初始化的过程...这就是多线程变量同步的问题。代码如下:public class AsyncMemberInitiation { static User user = null;
  • 处理器可以使用高速缓存加速对内存的访问(或者编译器可以将值存储到寄存器中以便进行更... 这表示在这样的系统上,对于同一变量,在两个不同处理器上执行的两个线程可能会看到两个不同的值! 解决这个问题的其中一个
  • ThreadLocal线程局部变量

    千次阅读 2014-09-24 11:00:00
    线程内的共享数据:原则 ---方法,表达式或者是模块,当他们在同一线程上运行,他们访问同一变量,应该访问的是同一数据。将数据与线程绑定到一起。换句话说,我线程内的事在我的线程内完成,不受其他线程的影响。...
  • 线程处理同一资源,但是任务不同 为什么要通信? 如果各个线程之间各干各的,确实不需要通信,这样的代码也十分的简单。但这一般是不可能的,至少线程要和主 线程进行通信,不然计算结果等内容无法取回。而...
  • java多线程(对象和变量的并发访问)

    万次阅读 2016-07-11 09:37:42
    在现实开发中,我们写的线程肯定会有不同的实例在执行,此时就可能会出现”非线程安全问题”,非线程安全就是:线程对同一个对象中的实例变量进行并发访问时候,有可能A和B线程同时读取到数据,先后进行更改,...
  • 如果两个线程试图几乎在同一时间对同一变量做增量操作而不进行同步的话,结果可能就不一致了,在上述代码中,我们传进线程函数的是变量的地址,那么变量i自增后,可能还没有写回内存单元,就被另一个线程读取了。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 104,332
精华内容 41,732
关键字:

多线程读取同一变量