Chinaunix首页 | 论坛 | 博客
  • 博客访问: 289998
  • 博文数量: 95
  • 博客积分: 618
  • 博客等级: 中士
  • 技术积分: 455
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-28 13:39
文章分类

全部博文(95)

文章存档

2015年(65)

2013年(1)

2012年(10)

2011年(19)

分类: LINUX

2015-06-24 12:10:57

多线程对全局字符串变量append造成的问题

最近在项目中使用多线程处理接收数据,运行时开始提示“数组越界”,之后有提示“内存访问冲突”“堆损坏”。通过分析发现是多个线程同时对一个全局String变量调用append方法造成的。下面详细说一下这个问题的原因。

首先用下面简单的伪代码说明函数库中用到的String类,为了简单起见,只写出了String的关键部分,省去了原函数库中的工具函数和边界检测。


点击(此处)折叠或打开

  1. class String
  2. {
  3.  public:
  4.   String& String::append(const String& s);
  5.  private:
  6.  char* d;
  7.  int size; //字符串d的长度
  8.  int alloc; //d指向空间的总大小(大于等于size)
  9. };
  10. String& String::append(const String& s)
  11. {
  12.   if(this->d==NULL){
  13.    *this=s;
  14.   }
  15.   else {
  16.    if( (this->size+s.size)>this->alloc)
  17.    {
  18.     char* temp=this->d;
  19.     realloc(this->d,this->size+s.size);
  20.     memcpy(this->d,temp,this->size);
  21.    }
  22.    memcpy(this->d+this->size,s.d,s.size);
  23.    this->size+=s.size;
  24.    this->d[this->size]='\0';
  25.  }
  26. return *this;
  27. }
  28. String str; //全局变量
  29. void* fun(void*)//多个线程函数
  30. {
  31.   String s=receive();//从套接字接收数据并存放在s中
  32.   str.append();//将s添加到str的结尾
  33. }

当同时有多个线程执行可能会造成错误。首先要说的是造成错误的原因并不是append中的realloc函数,当使用多线程时会连接多线程库,而多线程库的realloc是线程安全的(内部通过加锁保证互斥).

下面分析一下造成错误的原因:

(1) 假设当前strsize5alloc10

(2) 线程1执行appendssize3;线程2执行appendssize4

(3) 线程1执行到第16行: if( (this->size+s.size)>this->alloc),条件测试失败(因为3+5<10),此时切换到线程2执行;

(4) 线程2也执行到第16行: if( (this->size+s.size)>this->alloc),条件测试失败(因为4+5<10),然后直接向后执行memcpy(this->d+this->size,s.d,s.size);

此时size=4+5=9;

(5) 线程1向后执行memcpy(this->d+this->size,s.d,s.size),此时size=9+3=12,由于size已经大于alloc,所以数组越界造成内存错误。

    其实避免这种问题的方法很简单,当多个线程访问全局变量时加锁同步就可以解决。但是我觉得还是有必要知道为什么要加锁,不加锁会造成哪些问题。

阅读(1503) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~