社区
网络及通讯开发
帖子详情
关于多线程操作同一个队列时如何互斥
gungod
2011-06-29 10:15:55
有一个接收线程,一个队列,N个处理线程;
a.接收线程负责不断接收数据包写入队列;
b.处理线程从队列中读取数据包后,删除该数据包,再处理数据包;
关于队列的读写操作,我担心N个处理线程同时读取了队列的同一个数据包,做删除时,删除了未读取的数据包;
想加个一个保护,线程依次访问,是否应该用互斥,该如何写?
...全文
723
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
打赏
举报
回复
一般多线程中保持同步用的几种方式:
互斥,信号灯,临界,事件
秒杀
多线程
第十六篇
多线程
十大经典案例之一 双线程读写
队列
数据
在《秒杀
多线程
系列》的前十五篇中介绍
多线程
的相关概念,
多线程
同步
互斥
问题《秒杀
多线程
第四篇一个经典的
多线程
同步问题》及解决
多线程
同步
互斥
的常用方法——关键段、事件、
互斥
量、信号量、读写锁。为了让大家...
线程安全型
队列
的实现
在IT领域,线程安全是
多线程
编程中的一个重要概念,指的是当多个线程访问同一块资源
时
,代码能够正确地处理并发访问,避免数据不一致或死锁等问题。在这个"线程安全型
队列
"的课程设计中,我们将探讨如何在C语言环境...
C语言实现的
多线程
小程序
在C语言中实现
多线程
小程序是一项挑战性的任务,它涉及到
操作
系统级别的编程和并发控制。本项目主要关注的是线程间的
互斥
访问以及消息
队列
的使用,这在
多线程
编程中是至关重要的概念。 首先,让我们了解一下“线程...
计算机
操作
系统实验线程调度的优化和控制.doc
在每个
时
间片结束
时
,
操作
系统都会将当前线程暂停,并将下一个线程放到
队列
的头部,以便下一个
时
间片开始执行。这种算法的优点是简单易实现,但缺点是可能导致线程饥饿问题,即某些线程可能永远不能执行。 2. 四级...
java
多线程
(四)—— 线程同步/
互斥
=
队列
+锁
同步就是多个线程同
时
访问一个资源。那么如何实现?
队列
+锁。想要访问同一资源的线程排成一个
队列
,按照排队的顺序访问。访问的
时
候加上一个锁(参考卫生巾排队+锁门),访问完释放锁。
网络及通讯开发
1,317
社区成员
8,874
社区内容
发帖
与我相关
我的任务
网络及通讯开发
C++ Builder 网络及通讯开发
复制链接
扫一扫
分享
社区描述
C++ Builder 网络及通讯开发
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章