社区
网络及通讯开发
帖子详情
关于多线程操作同一个队列时如何互斥
gungod
2011-06-29 10:15:55
有一个接收线程,一个队列,N个处理线程;
a.接收线程负责不断接收数据包写入队列;
b.处理线程从队列中读取数据包后,删除该数据包,再处理数据包;
关于队列的读写操作,我担心N个处理线程同时读取了队列的同一个数据包,做删除时,删除了未读取的数据包;
想加个一个保护,线程依次访问,是否应该用互斥,该如何写?
...全文
663
20
打赏
收藏
关于多线程操作同一个队列时如何互斥
有一个接收线程,一个队列,N个处理线程; a.接收线程负责不断接收数据包写入队列; b.处理线程从队列中读取数据包后,删除该数据包,再处理数据包; 关于队列的读写操作,我担心N个处理线程同时读取了队列的同一个数据包,做删除时,删除了未读取的数据包; 想加个一个保护,线程依次访问,是否应该用互斥,该如何写?
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用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
打赏
举报
回复
一般多线程中保持同步用的几种方式:
互斥,信号灯,临界,事件
秒杀
多线程
第十六篇
多线程
十大经典案例之一 双线程读写
队列
数据
在《秒杀
多线程
系列》的前十五篇中介绍
多线程
的相关概念,
多线程
同步
互斥
问题《秒杀
多线程
第四篇一个经典的
多线程
同步问题》及解决
多线程
同步
互斥
的常用方法——关键段、事件、
互斥
量、信号量、读写锁。为了让大家...
C语言实现的
多线程
小程序
C语言实现
多线程
互斥
访问消息
队列
,程序中有一个应用消息
队列
,一个内核消息
队列
,3个线程,其中两个线程实现对应用消息
队列
的
互斥
访问,主要是运用
互斥
子
操作
C++11 14 17 20
多线程
从原理到线程池实战
学习计划 每天学习一小
时
以上 跟着视频动手编写代码 调试代码并对比课程多提供的源码 课程目标 理解
多线程
原理并学会c++11 的
多线程
编程 理解线程池技术原理并能使用c++实现 理解c++11 14 17 20
多线程
编程相关特性 常见问题 课程使用的开发工具? 课程使用的开发工具是vs2019 课程代码是否是跨平台? 课程代码都是基于c++自生特性,没有用到第三方库,都是跨平台 旧版本的开发工具是否可以? 课程中的大部分代码是c++11 ,绝大部分开发工具都支持,其中c++14 17要比较新的工具支持,c++20需要vs2019 课程是否提供源码? 课程提供源码,方便同学学习过程的出现问题,进行对照调试错误。
多线程
教程 各种锁 半成品的CAS 临界区 信号量 事件
互斥
锁
队列
多线程
教程 各种锁 半成品的CAS 临界区 信号量 事件
互斥
锁
队列
python
队列
queue模块详解
从queue
队列
的具体实现中,可以看出queue使用了1个线程
互斥
锁(pthread.Lock()),以及3个条件标量(pthread.condition()),来保证了线程安全。 queue
队列
的
互斥
锁和条件变量,可以参考另一篇文章:python线程中同步锁 ...
网络及通讯开发
1,316
社区成员
8,873
社区内容
发帖
与我相关
我的任务
网络及通讯开发
C++ Builder 网络及通讯开发
复制链接
扫一扫
分享
社区描述
C++ Builder 网络及通讯开发
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章