社区
网络及通讯开发
帖子详情
关于多线程操作同一个队列时如何互斥
gungod
2011-06-29 10:15:55
有一个接收线程,一个队列,N个处理线程;
a.接收线程负责不断接收数据包写入队列;
b.处理线程从队列中读取数据包后,删除该数据包,再处理数据包;
关于队列的读写操作,我担心N个处理线程同时读取了队列的同一个数据包,做删除时,删除了未读取的数据包;
想加个一个保护,线程依次访问,是否应该用互斥,该如何写?
...全文
703
20
打赏
收藏
关于多线程操作同一个队列时如何互斥
有一个接收线程,一个队列,N个处理线程; a.接收线程负责不断接收数据包写入队列; b.处理线程从队列中读取数据包后,删除该数据包,再处理数据包; 关于队列的读写操作,我担心N个处理线程同时读取了队列的同一个数据包,做删除时,删除了未读取的数据包; 想加个一个保护,线程依次访问,是否应该用互斥,该如何写?
复制链接
扫一扫
分享
转发到动态
举报
AI
作业
写回复
配置赞助广告
用AI写文章
20 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
gungod
2011-07-04
打赏
举报
回复
保护队列数据的互斥我应该是成功了,
效率问题跟这个无关,结贴了
laowang2
2011-07-01
打赏
举报
回复
学习学习。
Waiting4you
2011-07-01
打赏
举报
回复
[Quote=引用 12 楼 waiting4you 的回复:]
关于效率,有什么办法提高?
[/Quote]
stl的队列不是对多线程优化的,你可以到网上找找专门的多线程安全队列(比如TBB的无锁队列)。如果要求不是太高,你上面的代码也可以做一些简单的优化:
g_Lock->Acquire();
if(g_TcpDataQueue1.size()>0)
{
_AnalyseString = g_TcpDataQueue1.front();
g_TcpDataQueue1.pop();
}
g_Lock->Release();
改成
if(!g_TcpDataQueue1.empty())
{
g_Lock->Acquire();
if(!g_TcpDataQueue1.empty())
{
_AnalyseString = g_TcpDataQueue1.front();
g_TcpDataQueue1.pop();
}
g_Lock->Release();
}
这样可以避免空队列时多个线程不断地Acquire/Release
tst1255
2011-07-01
打赏
举报
回复
如果当初放入队列的时候是用new 或malloc 申请的内存,放入队列应该不会有问题,如果是把一个AnsiString使用c_str()方法转换成char *放入队列,那就可能有问题。
楼主的接收的数据包里都是字符信息码? 如果有二进制数据用string处理不是好方法。
通常情况下数据包需要自己定义协议,如命令类型、数据类型、数据长度之类的信息,纯字符的通信情况较少吧。
效率问题应该是根据通讯速率,每个数据包处理的时间,线程的多少去优化,不是线程越多越好。CPU的核就那几个,线程多了调度放入开销就大。如果每个包处理的时间很短,多线程还不如单线程效率高。
CppFile
2011-07-01
打赏
举报
回复
尽量少在acquire和release之间操作,让资源尽快释放给别的线程用
gungod
2011-07-01
打赏
举报
回复
[Quote=引用 12 楼 waiting4you 的回复:]
queue<char*> g_TcpDataQueue1,如果里面存放的是字符串的话,很有可能有问题,建议如string或String来代替char*
只要做到对g_TcpDataQueue1的存取全部位于g_Lock->Acquire()和g_Lock->Release();之间,那就不会有问题,就是效率可能会有点慢。
[/Quote]
的确是char*的问题,我没有new,呵呵,
关于效率,有什么办法提高?
gungod
2011-07-01
打赏
举报
回复
[Quote=引用 18 楼 microheart 的回复:]
可以用临界区变量TCriticalSection
定义全局变量
TCriticalSection *crtSection = new TCriticalSection();
线程中使用时代码如下示例:
crtSection->Enter();
__try
{
//队列操作;
}
__finally
{
crtSection->Leave();
}
最后程序结束时把这个……
[/Quote]
之所以用队列,就是因为它是FIFO,我只对队列首尾操作,应该比LIST快吧。
microheart
2011-07-01
打赏
举报
回复
可以用临界区变量TCriticalSection
定义全局变量
TCriticalSection *crtSection = new TCriticalSection();
线程中使用时代码如下示例:
crtSection->Enter();
__try
{
//队列操作;
}
__finally
{
crtSection->Leave();
}
最后程序结束时把这个临界区变量咔嚓了
delete crtSection;
当然也可以使用TThreadList来进行
使用方法为使用时用LockList()方法;
使用完成后使用UnlockList()方法;
另外就是如果使用TList类,删除数据从尾部操作效率会高得很多
如:
List->Delete(List->Count-1);
List->Delete(0);
以上两种操作,第一种效率会好很多,你懂得!
tst1255
2011-06-30
打赏
举报
回复
[Quote=引用 6 楼 gungod 的回复:]
引用 5 楼 ice 的回复:
class MyThread : public TThread
{
...
private:
TCriticalSection pLockX;
int x;
float y;
...
};
void __fastcall MyThread::Execute()
……
我现在用的就是临界区,但是……
[/Quote]
临界区变量定义在线程内吗?在哪里创建呢,你该不会是每个线程里都创建了一个临界区吧?线程各用各的临界区就起不到同步作用了。
定义全局临界区变量,访问共享资源时,进入该临界区,结束访问退出临界区。 线程间要使用同一个临界区才会有效果。
CppFile
2011-06-30
打赏
举报
回复
用了临界区,不应该冲突的,线程在碰到临界区资源的时候,会等待的
Waiting4you
2011-06-30
打赏
举报
回复
queue<char*> g_TcpDataQueue1,如果里面存放的是字符串的话,很有可能有问题,建议如string或String来代替char*
只要做到对g_TcpDataQueue1的存取全部位于g_Lock->Acquire()和g_Lock->Release();之间,那就不会有问题,就是效率可能会有点慢。
gungod
2011-06-30
打赏
举报
回复
[Quote=引用 5 楼 ice 的回复:]
class MyThread : public TThread
{
...
private:
TCriticalSection pLockX;
int x;
float y;
...
};
void __fastcall MyThread::Execute()
……
[/Quote]
我现在用的就是临界区,但是还是有冲突,开始我还以为临界区是只是保护资源,线程不等待的。
估计还有冲突的。
tst1255
2011-06-30
打赏
举报
回复
读、写线程都要使用临界区
队列的指针是指向一个个的数据包吧,它们是接收线程加进去的,正好都是一个个独立的数据包吗?
“队列处理老是少了数据”是指队列里的数据包数少了,还是一个数据包里的数据少了。是不是接收线程没有分包好,把几个包的数据当成一个包插入到队列里了?
处理线程得到数据包后检查一下数据包的数据,有没有把两个包放在一起的可能。
gungod
2011-06-30
打赏
举报
回复
g_Lock是临界区对象,TcpDataQueue1是queue,
它们都是全局变量,
extern queue<char*> g_TcpDataQueue1; //TCP接收数据包队列
extern TCriticalSection *g_Lock; //临界区
g_Lock = new TCriticalSection ();
g_TcpDataQueue1倒是没有设置最大数目,难道是这个问题?
gungod
2011-06-30
打赏
举报
回复
我的处理线程,负责取出队列头部的数据,并把队头的数据删除;
g_Lock是临界区对象,TcpDataQueue1是queue,
当我发现我读取这个队列处理老是少了数据,是不是下面的写法不对?
g_Lock->Acquire();
if(g_TcpDataQueue1.size()>0)
{
_AnalyseString = g_TcpDataQueue1.front();
g_TcpDataQueue1.pop();
}
g_Lock->Release();
CppFile
2011-06-29
打赏
举报
回复
用临界区API
void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
就这么几个函数
每个线程要操作队列的时候,enter操作完毕后leave
开始领悟
2011-06-29
打赏
举报
回复
class MyThread : public TThread
{
...
private:
TCriticalSection pLockX;
int x;
float y;
...
};
void __fastcall MyThread::Execute()
{
...
pLockX-> Acquire();//Here pLockX is a Global CriticalSection variable.
x++;
y=sin(x);
pLockX-> Release();
...
}
tst1255
2011-06-29
打赏
举报
回复
BCB有一个 TThreadList对象,它是线程安全的,不需要再使用其它同步方法了。
sczyq
2011-06-29
打赏
举报
回复
用 TThreadList 来管理
TMyStruct * AStruct = NULL;
try
{
TList * AList = FThreadList->LockList();
if (AList->Count)
{
AStruct = (TMyStruct *)AList->Items[0];
AList->Delete(0);
}
}
__finally
{
FThreadList->UnlockList();
}
if (AStruct)
{
// 处理这个 AStruct
delete AStruct;
}
ccrun.com
2011-06-29
打赏
举报
回复
一般多线程中保持同步用的几种方式:
互斥,信号灯,临界,事件
秒杀
多线程
第十六篇
多线程
十大经典案例之一 双线程读写
队列
数据
《秒杀
多线程
第十六篇
多线程
十大经典案例之一 双线程读写
队列
数据》 http://blog.csdn.net/morewindows/article/details/8646902 配套程序 在《秒杀
多线程
系列》的前十五篇中介绍
多线程
的相关概念,
多线程
同步
互斥
问题《秒杀
多线程
第四篇一个经典的
多线程
同步问题》及解决
多线程
同步
互斥
的常用方法——关键段、事件、
互斥
量、信号量、读写锁。为了让大家更加熟练运用
多线程
,将会有十篇文章来讲解十个
多线程
使用案例,相信看完这十篇后会让你能更加游刃有余的使用
多线程
。
线程安全型
队列
的实现
操作
系统课程设计线程安全型
队列
,利用读者优先机制实现
互斥
。
C++实现线程安全
队列
使用
互斥
变量技术完成C++安全
队列
,同
时
编写测试代码进行此
队列
的测试。
C语言实现的
多线程
小程序
C语言实现
多线程
互斥
访问消息
队列
,程序中有一个应用消息
队列
,一个内核消息
队列
,3个线程,其中两个线程实现对应用消息
队列
的
互斥
访问,主要是运用
互斥
子
操作
构建C++线程安全
队列
:深入实现与代码实践
通过本文的介绍和代码示例,读者应该能够理解如何在C++中实现一个线程安全的
队列
,并掌握相关的同步机制。线程安全
队列
是
多线程
编程中的一个重要组件,正确实现它对于构建稳定可靠的并发程序至关重要。
网络及通讯开发
1,317
社区成员
8,874
社区内容
发帖
与我相关
我的任务
网络及通讯开发
C++ Builder 网络及通讯开发
复制链接
扫一扫
分享
社区描述
C++ Builder 网络及通讯开发
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章