是因为代码是vc写的原因么?很难么?怎么只有Another_eYes一人回答呢? (50分)

  • 主题发起人 坏蛋是我
  • 开始时间

坏蛋是我

Unregistered / Unconfirmed
GUEST, unregistred user!
(代码适用VC写的,不好意思)

小弟初涉多线程,问题如下:

我的程序要从数据包接收卡里面接收并处理数据,
每当有数据包到时,系统发出PostMessage(WM_PACKET_ARRIVED, 0, 0);
在这个消息的处理函数里面进行数据存储与转发。
我处理如下:
//数据包到达消息处理函数
int CReceiveApp::OnPacketArrived(WPARAM wParam, LPARAM lParam)
{
char filename[255];
struct AbcPacket Packet;
//initializtion...
//.......
//获取数据包
GetMyPacket(&Packet);
switch(Packet.PacketType)
{
case PACKET_A_TYPE:
Afxbegin
Thread(SavePacket_A,(LPVOID)&Packet);
break;
case PACKET_B_TYPE:
Afxbegin
Thread(SavePacket_B,(LPVOID)&Packet);
break;
case PACKET_C_TYPE:
Afxbegin
Thread(SavePacket_C,(LPVOID)&Packet);
break;
}
return 0;
}
//数据包A保存函数
UINT SavePacket_A(LPVOID param)
{
//...
return 0;
}
//数据包B保存函数
UINT SavePacket_B(LPVOID param)
{
//...
return 0;
}
//数据包C保存函数
UINT SavePacket_C(LPVOID param)
{
//...
return 0;
}
这样的处理方式会碰到什么问题么?
比如某一段时间内数据包(类型PACKET_B_TYPE)频繁到达,
那么与之对应的数据包保存线程函数SavePacket_B()会出现什么问题呢?
我把相同类型的数据包保存到同一个文件里面,
这样是不是造成冲突?线程同步控制我略知一二,我想知道上面的处理模式
对不对?应该怎样进行线程同步控制?

//////////////////////////////////////////////////////////
另外一个问题如下:
struct ThreadParam Param;
for (i=0;
i<10;
i++)
{
Param.index=i;
Afxbegin
Thread(ThreadFunc,(LPVOID)&amp;Param);
}

UINT ThreadFunc(LPVOID param)
{
FILE *stream;
char buffer[32];
char FileName[255];

//initializtion...
//.......

InitializeCriticalSection(&amp;g_cs);
EnterCriticalSection(&amp;g_cs);
if((stream=fopen(FileName, "a+" ))!=NULL)
{
sprintf((char *)buffer, "now is : %d/n", param->index);
fseek(stream, 0L, SEEK_END);
fwrite(buffer, sizeof(char), strlen(buffer), stream);
fclose(stream);
}
LeaveCriticalSection(&amp;g_cs);
return 0;
}
为什么运行后在文件(FileName)里面是:
now is : 1
now is : 2
now is : 3
now is : 4
now is : 5
now is : 6
now is : 7
now is : 8
now is : 9
now is : 9
//或者其他情况
而不是我想的结果?
now is : 0
now is : 1
now is : 2
now is : 3
now is : 4
now is : 5
now is : 6
now is : 7
now is : 8
now is : 9
呢?怎样纠正?

谢谢!
/////////////////////////////////////////////
另外,针对多线程各位能不能给点总结?
 
居然没人回复?csdn上回复的不少哦!
 
>>这样是不是造成冲突?

>>我想知道上面的处理模式对不对?
也许有问题。vc不熟, 关键是Packet这个局部变量是否会在线程执行到其中数据前就被释放了。 (因为OnPacketArrived并不等待而Packet在OnPacketArrived结束时已经超出它的作用域了,很可能被vc的内存管理自动释放,而此时线程中可能还未来得及使用它呢)
>>应该怎样进行线程同步控制?
保证一个线程写完文件前要写相同文件的第二个线程等待。
>>另外一个问题
你只同步了写文件这个操作而没有保护Param.Index这个变量。 在线程等待同步的过程中(或者线程刚生成还未来得及执行其中的具体代码之前)Param.Index可能已经被主程序改变了。
上述两个问题都是你使用了相对于不同线程来说是全局共享的变量(因为你传递的都是指针)而造成的。
 
欢迎讨论!
 
到达的数据量是否很大?数据是如何到达的,是并行的吗?
是如何接收数据的,接受的数据是从接收缓冲区取得的吗,是否所有端口使用同一个接收缓冲区?
是否进行过实际的测试?
 
1)了解你的思路了,想提点建议:
OnPacketArrived:数据包到达-》动态申请新空间存放-》加入接收队列;
一个线程(从程序开始就一直运行)循环检测接收队列,若有数据则将数据包从队列摘出,
写入文件,并释放存储空间;
这是典型的”生产者、消费者”模型,所以接收队列必须用互斥量或信号量来控制。
你的想法似乎是对的,但是
(1)忘了I/O操作远比内存操作慢,
(2)线程太多(在数据包频繁到达时)也会影响系统性能的。
(3)给线程使用的内存地址是函数私有的,下个数据包到达时就会改变其内容,这是不安全的。
2)这个问题Another_eYes, 已经说了一点;
还有就是,你顺序创建的线程并不是按你所以为的按顺序执行,这是我写程序时才发现的。
以上,仅是我看后的想法,还没试验过,不当之处请大家指出。
 
谢谢huntor的意见!
 
听君一席话,受益无穷啊!
 
前段写了代码,用D写的,也出现过这个问题,也是在Thread中PostMessage给主线程接收数据,
跟你的情况类似,然后在主线程中再转回所需要的数据,后来发现操作太频繁,数据出错。
像这样:
procedure Thread.SomeProc;
var
Value: TRecordData;
begin
Value...
PostMessage(MainThread_Form_Handle, WM_Msg, 0, Integer(@Value);
end;

在主线程中转这个Msg.LParam,发现N多个错。。。

后来就使用指针,然后再发给主线程,主线程接收到后处理再Free.
var
Value: PRecordData;
begin
new(Value);
Value...
PostMessage(MainThread_Form_Handle, WM_Msg, 0, Integer(Value);
end;

procedure TMain.ReceiveMsg(var msg: TMessage);
var
data: PRecordData;
begin
data := Pointer(msg.LParam);
// proc data ...
FreeMem(data);
end;
你的第二个问题类似,如果你的参数不多的话,你可以直接使用PostMessage的两个参数,
然后再转。因为线程的运行的不确定性,所以最好一个线程使用一个独立的变量。
或者new一个变量给线程,由线程再free.

如果线程使用频繁的话,建议使用线程池,自已实现一个了,如果资源有限的话,建议
在线程池的控制一下最大的线程数量。不然程序占用大量的线程不太好。

线程池我有Delphi/CB的代码,是继承TThread写的,可能有点帮助。
CB: http://www.playicq.com/dispdoc.php?t=&amp;id=2528
Delphi: http://www.playicq.com/dispdoc.php?t=&amp;id=1796
 
多人接受答案了。
 
顶部