再问STL中map的使用
-
- 帖子: 448
- 注册时间: 2008-07-10 15:08
再问STL中map的使用
//将struct作为map的成员,在将struct添加到map中后是否还可以自由修改struct的变量
#include<iostream>
#include<string>
#include<map>
using namespace std;
struct CTest
{
int i;
char a[16];
};
map<int ,CTest*> map_struct;
int main()
{
CTest* ct=new CTest;
ct->i=10;
strncpy(ct->a,"192.168.3.32",strlen("192.168.3.32"));
pair<map<int,CTest*>::iterator,bool> insert_pair;
insert_pair=map_struct.insert(map<int,CTest*>::value_type(ct->i,ct));
map<int,CTest*>::iterator iter;
if(true==insert_pair.second)
cout<<"插入数据成功\n";
else
cout<<"插入数据失败\n";
for(iter=map_struct.begin();iter!=map_struct.end();iter++)
cout<<iter->first<<"\t"<<(iter->second)->i<<"\t"<<(iter->second)->a<<endl;
//现在私下修改struct的数据
ct->i=199;
strncpy(ct->a,"192.168.3.31",strlen("192.168.3.31"));
///试验证明在不惊动map的情况下仍然可以对struct的变量进行修改,
//只有对map进行添加或着删除的时候才会影响到:
for(iter=map_struct.begin();iter!=map_struct.end();iter++)
cout<<iter->first<<"\t"<<(iter->second)->i<<"\t"<<(iter->second)->a<<endl;
return 0;
}
因为在多线程的编程时候,可能同时有多个线程要使用、修改map我给它加个锁,在比如删除、插入、map.find()、map.size()等操作时要锁住后在操作,一旦将变量添加到map中比如我的struct CTest ct 的变量对它进行操作的时候,可能还需要一个内部锁防止多个线程对其操作,
我问在我对struct CTest ct的变量修改的时候我在锁住内部锁之前是不是还得锁住维护map的锁哪?
#include<iostream>
#include<string>
#include<map>
using namespace std;
struct CTest
{
int i;
char a[16];
};
map<int ,CTest*> map_struct;
int main()
{
CTest* ct=new CTest;
ct->i=10;
strncpy(ct->a,"192.168.3.32",strlen("192.168.3.32"));
pair<map<int,CTest*>::iterator,bool> insert_pair;
insert_pair=map_struct.insert(map<int,CTest*>::value_type(ct->i,ct));
map<int,CTest*>::iterator iter;
if(true==insert_pair.second)
cout<<"插入数据成功\n";
else
cout<<"插入数据失败\n";
for(iter=map_struct.begin();iter!=map_struct.end();iter++)
cout<<iter->first<<"\t"<<(iter->second)->i<<"\t"<<(iter->second)->a<<endl;
//现在私下修改struct的数据
ct->i=199;
strncpy(ct->a,"192.168.3.31",strlen("192.168.3.31"));
///试验证明在不惊动map的情况下仍然可以对struct的变量进行修改,
//只有对map进行添加或着删除的时候才会影响到:
for(iter=map_struct.begin();iter!=map_struct.end();iter++)
cout<<iter->first<<"\t"<<(iter->second)->i<<"\t"<<(iter->second)->a<<endl;
return 0;
}
因为在多线程的编程时候,可能同时有多个线程要使用、修改map我给它加个锁,在比如删除、插入、map.find()、map.size()等操作时要锁住后在操作,一旦将变量添加到map中比如我的struct CTest ct 的变量对它进行操作的时候,可能还需要一个内部锁防止多个线程对其操作,
我问在我对struct CTest ct的变量修改的时候我在锁住内部锁之前是不是还得锁住维护map的锁哪?
- BigSnake.NET
- 帖子: 12522
- 注册时间: 2006-07-02 11:16
- 来自: 廣州
- 联系:
Re: 再问STL中map的使用
这个肯定是可以的, map 不可能知道你外面还有个指针指着 ct
map::operator [] 返回的也是值类型的引用,可以当左值用
PS: 内存泄漏了
map::operator [] 返回的也是值类型的引用,可以当左值用
PS: 内存泄漏了
^_^ ~~~
要理解递归,首先要理解递归。
地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。
要理解递归,首先要理解递归。
地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。
-
- 帖子: 8
- 注册时间: 2008-11-16 20:13
Re: 再问STL中map的使用
LZ对map的理解不够深刻,所以才会有“惊动map”的想法。
map仅仅是一个容器,也就是说 它更本不关心你放了什么进去。
map的实现 完全可以理解为 一个有序链表,即:list + index (表+索引)的结构。
而map对index的默认实现,仅仅是有序表的操作。
对于多线程应用程序的实现,程序结构设计非常重要。其重点在于 “临界区资源” 的访问。
程序员需要 考虑 那些是临界区资源 那些操作需要互斥,那些数据需要同步。
容器的使用 仅仅是数据的组织方式 二者不是一个范畴。
map仅仅是一个容器,也就是说 它更本不关心你放了什么进去。
map的实现 完全可以理解为 一个有序链表,即:list + index (表+索引)的结构。
而map对index的默认实现,仅仅是有序表的操作。
对于多线程应用程序的实现,程序结构设计非常重要。其重点在于 “临界区资源” 的访问。
程序员需要 考虑 那些是临界区资源 那些操作需要互斥,那些数据需要同步。
容器的使用 仅仅是数据的组织方式 二者不是一个范畴。
- xhy
- 帖子: 3916
- 注册时间: 2005-12-28 1:16
- 系统: Ubuntu 12.10 X64
- 来自: 火星
Re: 再问STL中map的使用
STL的Map实现是红黑树或者平衡二叉树
容器的操作是不是thread-safe 得看实现
标准C++里没有线程这个概念,也不支持多线程
j建议假定STL不是线程安全 自己加锁比较保险
容器的操作是不是thread-safe 得看实现
标准C++里没有线程这个概念,也不支持多线程
j建议假定STL不是线程安全 自己加锁比较保险
目前负债150多万
-
- 帖子: 448
- 注册时间: 2008-07-10 15:08
Re: 再问STL中map的使用
Wayne.viichi,
你说我开启多个线程的话是不是应该把map看成是“临界区资源”哪?
多个线程同时使用这个map的啊,是不是在map.erase()时候因该加锁
还有我在调用map.size()是不是同样也得考虑锁住map再使用?
你说我开启多个线程的话是不是应该把map看成是“临界区资源”哪?
多个线程同时使用这个map的啊,是不是在map.erase()时候因该加锁
还有我在调用map.size()是不是同样也得考虑锁住map再使用?
-
- 帖子: 8
- 注册时间: 2008-11-16 20:13
Re: 再问STL中map的使用
我的通常做法是:
class CCriticalData
{
public:
bool Init();
void Clear();
void Lock();
void Unlock();
//your data..
int A;
map<int, int> myMap;
};
CCriticalData cd;
cd.Init();
//....
// the one thread.
cd.Lock();
cd.A = 20;
cl.myMap.insert(...);
//...
cl.Unlock();
// the others thread.
cd.Lock();
cd.A += 20;
cd.myMap.find(10);
//...
cd.Unlock();
在一般应用中,容器本身的线程安全是没有实际意义的。因为它无法保证你元素数据的线程安全。
临界区的应用在于,确定每个临界区的范围(其中包含的数据),使其交集最小。
这里的交集是指同时进入临界区的交集。比如 临界区A中包含a,B包含b,C包含c,同时操作a,b或c就产生了临界区交集。
交集过多,则可能导致死锁。临界区数量过少导致性能低下。
class CCriticalData
{
public:
bool Init();
void Clear();
void Lock();
void Unlock();
//your data..
int A;
map<int, int> myMap;
};
CCriticalData cd;
cd.Init();
//....
// the one thread.
cd.Lock();
cd.A = 20;
cl.myMap.insert(...);
//...
cl.Unlock();
// the others thread.
cd.Lock();
cd.A += 20;
cd.myMap.find(10);
//...
cd.Unlock();
在一般应用中,容器本身的线程安全是没有实际意义的。因为它无法保证你元素数据的线程安全。
临界区的应用在于,确定每个临界区的范围(其中包含的数据),使其交集最小。
这里的交集是指同时进入临界区的交集。比如 临界区A中包含a,B包含b,C包含c,同时操作a,b或c就产生了临界区交集。
交集过多,则可能导致死锁。临界区数量过少导致性能低下。
-
- 帖子: 448
- 注册时间: 2008-07-10 15:08
Re: 再问STL中map的使用
Wayne.viichi,
你说的额容器本省的线程安全是没有实际意义的我不是很赞同
难道可以允许多个线程同时对一个map进行insert,find,erase操作吗?不是吧
我看了你的实例,每次你对
map的操作钱都加了锁,而在操作完成后解锁,当然在锁住的同时不光对map的insert。erase操作,还有对数据的操作
我也直到你加锁不加锁,对于存放的数据本身的安全性起不到实际的保护作用,
但是单纯的说对于同一个map的insert和erase操作是不是应该加锁,以免同时有多个线程对map进行操作?
'我说的是不是阿?
你说的额容器本省的线程安全是没有实际意义的我不是很赞同
难道可以允许多个线程同时对一个map进行insert,find,erase操作吗?不是吧
我看了你的实例,每次你对
map的操作钱都加了锁,而在操作完成后解锁,当然在锁住的同时不光对map的insert。erase操作,还有对数据的操作
我也直到你加锁不加锁,对于存放的数据本身的安全性起不到实际的保护作用,
但是单纯的说对于同一个map的insert和erase操作是不是应该加锁,以免同时有多个线程对map进行操作?
'我说的是不是阿?
-
- 帖子: 8
- 注册时间: 2008-11-16 20:13
- xhy
- 帖子: 3916
- 注册时间: 2005-12-28 1:16
- 系统: Ubuntu 12.10 X64
- 来自: 火星
Re: 再问STL中map的使用
锁会导致性能低下,实际工作中线程很少需要读写同一套数据,线程是用来解决io等待的。weihua2008 写了:Wayne.viichi,
你说的额容器本省的线程安全是没有实际意义的我不是很赞同
难道可以允许多个线程同时对一个map进行insert,find,erase操作吗?不是吧
我看了你的实例,每次你对
map的操作钱都加了锁,而在操作完成后解锁,当然在锁住的同时不光对map的insert。erase操作,还有对数据的操作
我也直到你加锁不加锁,对于存放的数据本身的安全性起不到实际的保护作用,
但是单纯的说对于同一个map的insert和erase操作是不是应该加锁,以免同时有多个线程对map进行操作?
'我说的是不是阿?
尽量减少线程的使用,尽量减小锁的粒度。
目前负债150多万
-
- 帖子: 448
- 注册时间: 2008-07-10 15:08
Re: 再问STL中map的使用
xhy,
说的有道理,但是我至少要两个线程才能完成功能,而且在这两个线程中都有可能对map进行insert和erase操作
那么加锁是不是必须的,没有锁的话就不能保证操作的正确性了不是
就是在这两个线程中用锁我都上愁,下面是一个很伤脑筋的例子
bool CTest::DeleteFromMap(int nSocketFd)
{
map<int, tagServSockContext*>::iterator iter;
pthread_mutex_lock(&(m_MapLock));
iter=m_Map.find(nSocketFd);
pthread_mutex_unlock(&(m_MapLock));
if(iter!=m_tMap.end())
{ //从m_Map中将相关信息删除
pthread_mutex_lock(&(m_MapLock));
int i= m_Map.erase(nSocketFd);
pthread_mutex_unlock(&(m_MapLock));
if(i==1)
{
//关闭文件描述符
close(nSocketFd);
FreetagServSockContext(ptagServSockContext);//释放内存包括消毁内部锁
return true;
}
else//i==0
{
cout<<"m_Map中删除相关信息失败\n";
return false;
}
}
else//if(iter==m_map.end())
{
cout<<"在m_map中没有对象可删除\n";
return false;
}
}
还是这样做好哪?
bool CTest::DeleteFromMap(int nSocketFd)
{
map<int, tagServSockContext*>::iterator iter;
pthread_mutex_lock(&(m_MapLock));
iter=m_Map.find(nSocketFd);
if(iter!=m_Map.end())
{ //从m_Map中将相关信息删除
int i= m_Map.erase(nSocketFd);
pthread_mutex_unlock(&(m_MapLock));
if(i==1)
{
//关闭文件描述符
close(nSocketFd);
FreetagServSockContext(ptagServSockContext);//释放内存包括消毁内部锁
return true;
}
else//i==0
{
cout<<"m_Map中删除相关信息失败\n";
return false;
}
}
else//iter==m_map.end()
{ pthread_mutex_unlock(&(m_MapLock));
cout<<"在m_map中没有对象可删除\n";
return false;
}
}
说说大家的看法...............
说的有道理,但是我至少要两个线程才能完成功能,而且在这两个线程中都有可能对map进行insert和erase操作
那么加锁是不是必须的,没有锁的话就不能保证操作的正确性了不是
就是在这两个线程中用锁我都上愁,下面是一个很伤脑筋的例子
bool CTest::DeleteFromMap(int nSocketFd)
{
map<int, tagServSockContext*>::iterator iter;
pthread_mutex_lock(&(m_MapLock));
iter=m_Map.find(nSocketFd);
pthread_mutex_unlock(&(m_MapLock));
if(iter!=m_tMap.end())
{ //从m_Map中将相关信息删除
pthread_mutex_lock(&(m_MapLock));
int i= m_Map.erase(nSocketFd);
pthread_mutex_unlock(&(m_MapLock));
if(i==1)
{
//关闭文件描述符
close(nSocketFd);
FreetagServSockContext(ptagServSockContext);//释放内存包括消毁内部锁
return true;
}
else//i==0
{
cout<<"m_Map中删除相关信息失败\n";
return false;
}
}
else//if(iter==m_map.end())
{
cout<<"在m_map中没有对象可删除\n";
return false;
}
}
还是这样做好哪?
bool CTest::DeleteFromMap(int nSocketFd)
{
map<int, tagServSockContext*>::iterator iter;
pthread_mutex_lock(&(m_MapLock));
iter=m_Map.find(nSocketFd);
if(iter!=m_Map.end())
{ //从m_Map中将相关信息删除
int i= m_Map.erase(nSocketFd);
pthread_mutex_unlock(&(m_MapLock));
if(i==1)
{
//关闭文件描述符
close(nSocketFd);
FreetagServSockContext(ptagServSockContext);//释放内存包括消毁内部锁
return true;
}
else//i==0
{
cout<<"m_Map中删除相关信息失败\n";
return false;
}
}
else//iter==m_map.end()
{ pthread_mutex_unlock(&(m_MapLock));
cout<<"在m_map中没有对象可删除\n";
return false;
}
}
说说大家的看法...............
-
- 帖子: 8
- 注册时间: 2008-11-16 20:13
Re: 再问STL中map的使用
呵呵,我是一个Win32程序员,linux是一个新手..xhy 写了:锁会导致性能低下,实际工作中线程很少需要读写同一套数据,线程是用来解决io等待的。weihua2008 写了:Wayne.viichi,
你说的额容器本省的线程安全是没有实际意义的我不是很赞同
难道可以允许多个线程同时对一个map进行insert,find,erase操作吗?不是吧
我看了你的实例,每次你对
map的操作钱都加了锁,而在操作完成后解锁,当然在锁住的同时不光对map的insert。erase操作,还有对数据的操作
我也直到你加锁不加锁,对于存放的数据本身的安全性起不到实际的保护作用,
但是单纯的说对于同一个map的insert和erase操作是不是应该加锁,以免同时有多个线程对map进行操作?
'我说的是不是阿?
尽量减少线程的使用,尽量减小锁的粒度。
在win32下开发服务器程序,通常使用完成端口,这样操作数据的线程是完全不确定的..
在linux下 可能我的这个想法好改一改 呵呵..
在多核时代,多线程的使用可以大幅度提高程序运行效率,但线程安全也随之变成了首要的问题。
刚刚查到.. linux下与Win32完成端口功能相似的接口,epoll。
大家以后多多交流..
- xhy
- 帖子: 3916
- 注册时间: 2005-12-28 1:16
- 系统: Ubuntu 12.10 X64
- 来自: 火星
Re: 再问STL中map的使用
epoll是最近几年才有的,以前都是那该死的poll和select,性能低下。Wayne.viichi 写了:呵呵,我是一个Win32程序员,linux是一个新手..xhy 写了:锁会导致性能低下,实际工作中线程很少需要读写同一套数据,线程是用来解决io等待的。weihua2008 写了:Wayne.viichi,
你说的额容器本省的线程安全是没有实际意义的我不是很赞同
难道可以允许多个线程同时对一个map进行insert,find,erase操作吗?不是吧
我看了你的实例,每次你对
map的操作钱都加了锁,而在操作完成后解锁,当然在锁住的同时不光对map的insert。erase操作,还有对数据的操作
我也直到你加锁不加锁,对于存放的数据本身的安全性起不到实际的保护作用,
但是单纯的说对于同一个map的insert和erase操作是不是应该加锁,以免同时有多个线程对map进行操作?
'我说的是不是阿?
尽量减少线程的使用,尽量减小锁的粒度。
在win32下开发服务器程序,通常使用完成端口,这样操作数据的线程是完全不确定的..
在linux下 可能我的这个想法好改一改 呵呵..
在多核时代,多线程的使用可以大幅度提高程序运行效率,但线程安全也随之变成了首要的问题。
刚刚查到.. linux下与Win32完成端口功能相似的接口,epoll。
大家以后多多交流..
有评测数据,epoll和kqueue的性能不相上下,非常彪悍。
更方便的办法是用libevent这个库,它封装了常见的事件通知机制。
多线程能不能提高程序的性能很难说,如果问题本身就具有原子性,不能分割,多线程就没有意义。
linux和unix传统倾向于多进程的使用,而非多线程。
目前负债150多万
- xhy
- 帖子: 3916
- 注册时间: 2005-12-28 1:16
- 系统: Ubuntu 12.10 X64
- 来自: 火星
Re: 再问STL中map的使用
代码: 全选
pthread_mutex_lock(&(m_MapLock));
m_Map.erase(nSocketFd);
pthread_mutex_unlock(&(m_MapLock));
目前负债150多万
-
- 帖子: 448
- 注册时间: 2008-07-10 15:08
Re: 再问STL中map的使用
xhy,
单纯的对于一个删除map中数据的操作,可能我做的有点复杂,
我还是没有把问题说明白,或者说我的的疑问所在,我的疑问可能就是 你说道尽量减少锁的粒度,
你抛开我的程序的不提,你说使用锁的时候更倾向于第一种使用方法还是第二种使用方法
第一种:尽量减少锁的粒度,就是哪怕我在一个函数中(多锁住几次多释放几次)也不会(少锁住几次,叫每次锁住的时间长一点),
第二种:在一个函数中比较接近的操作我只锁住一次锁,把一个或者两个操作完成后在释放锁,
你说是加锁解锁锁用的时间长还是,程序运作的时间长?
1.pthread_mutex_lock(&(m_MapLock));
iter=m_Map.find(nSocketFd);
pthread_mutex_unlock(&(m_MapLock));
if(iter!=m_tMap.end())
{ //从m_Map中将相关信息删除
pthread_mutex_lock(&(m_MapLock));
int i= m_Map.erase(nSocketFd);
pthread_mutex_unlock(&(m_MapLock));
//////////////////////////////////////////////////////////////////////////
2.pthread_mutex_lock(&(m_MapLock));
iter=m_Map.find(nSocketFd);
if(iter!=m_Map.end())
{ //从m_Map中将相关信息删除
int i= m_Map.erase(nSocketFd);
pthread_mutex_unlock(&(m_MapLock));
这两种方式各位喜欢哪种,不能说喜欢,应该说按道理来说应该选择哪种方式?(仅从逻辑和效率上考虑两者的舍取)
、、、、、、、、、、、、、、、、。。。。
其实我觉得我程序的第一种方式就不对,或者说就不严谨,
你比如说我先锁住map,判断一下map中有没有要找的东西a,我就放开了,接着又一个线程又锁住了map也同样的判断map中有没有要找的这个东西a,第二个线程也放开了锁,第一个线程又锁住了锁,该线程在第一次解锁后判断了一下函数的返回值一看有要找的东西a,在第二次锁住后把找到的数据a删除了,第二个线程在第一次解锁后分析函数的返回值也同样得出map有要找的东西a的论断,结果他在第二次锁住map后也会调用删除数据a的函数进行删除,其实此时数据a已经被第一个线程删除了,这是我的遐想,把事情想的太坏了,但我认为这个问题的发生是有可能的,所以应该是锁住map后判断有没有要找的数据,有的话删除以后再解锁,没有的话就直接解锁
我说明白了吗,
还是希望智者帮我分析一下锁的使用原则,
单纯的对于一个删除map中数据的操作,可能我做的有点复杂,
我还是没有把问题说明白,或者说我的的疑问所在,我的疑问可能就是 你说道尽量减少锁的粒度,
你抛开我的程序的不提,你说使用锁的时候更倾向于第一种使用方法还是第二种使用方法
第一种:尽量减少锁的粒度,就是哪怕我在一个函数中(多锁住几次多释放几次)也不会(少锁住几次,叫每次锁住的时间长一点),
第二种:在一个函数中比较接近的操作我只锁住一次锁,把一个或者两个操作完成后在释放锁,
你说是加锁解锁锁用的时间长还是,程序运作的时间长?
1.pthread_mutex_lock(&(m_MapLock));
iter=m_Map.find(nSocketFd);
pthread_mutex_unlock(&(m_MapLock));
if(iter!=m_tMap.end())
{ //从m_Map中将相关信息删除
pthread_mutex_lock(&(m_MapLock));
int i= m_Map.erase(nSocketFd);
pthread_mutex_unlock(&(m_MapLock));
//////////////////////////////////////////////////////////////////////////
2.pthread_mutex_lock(&(m_MapLock));
iter=m_Map.find(nSocketFd);
if(iter!=m_Map.end())
{ //从m_Map中将相关信息删除
int i= m_Map.erase(nSocketFd);
pthread_mutex_unlock(&(m_MapLock));
这两种方式各位喜欢哪种,不能说喜欢,应该说按道理来说应该选择哪种方式?(仅从逻辑和效率上考虑两者的舍取)
、、、、、、、、、、、、、、、、。。。。
其实我觉得我程序的第一种方式就不对,或者说就不严谨,
你比如说我先锁住map,判断一下map中有没有要找的东西a,我就放开了,接着又一个线程又锁住了map也同样的判断map中有没有要找的这个东西a,第二个线程也放开了锁,第一个线程又锁住了锁,该线程在第一次解锁后判断了一下函数的返回值一看有要找的东西a,在第二次锁住后把找到的数据a删除了,第二个线程在第一次解锁后分析函数的返回值也同样得出map有要找的东西a的论断,结果他在第二次锁住map后也会调用删除数据a的函数进行删除,其实此时数据a已经被第一个线程删除了,这是我的遐想,把事情想的太坏了,但我认为这个问题的发生是有可能的,所以应该是锁住map后判断有没有要找的数据,有的话删除以后再解锁,没有的话就直接解锁
我说明白了吗,
还是希望智者帮我分析一下锁的使用原则,
- xhy
- 帖子: 3916
- 注册时间: 2005-12-28 1:16
- 系统: Ubuntu 12.10 X64
- 来自: 火星
Re: 再问STL中map的使用
map是不需要判断元素是否存在的,可以直接删除
虽然map里面a[3]并不存在,但是去erase它也不会有什么副作用。
所以你只需要
就可以了
简而言之,锁用的越少越好,每次锁住的时间越短越好。
代码: 全选
#include <iostream>
#include <map>
int main()
{
std::map <int, int> a;
a[1] = 1000;
a[2] = 2000;
std::cout<<a[1]<<std::endl;
std::cout<<a[2]<<std::endl;
a.erase(1);
a.erase(3);
std::cout<<a[1]<<std::endl;
std::cout<<a[2]<<std::endl;
}
所以你只需要
代码: 全选
pthread_mutex_lock(&(m_MapLock));
m_Map.erase(nSocketFd);
pthread_mutex_unlock(&(m_MapLock));
简而言之,锁用的越少越好,每次锁住的时间越短越好。
目前负债150多万