C# 多线程执行过程探讨

SuperHero乐成 2012-10-14 02:42:44
上代码说明问题

class Program
{
static Thread t1 = new Thread(new ThreadStart(Run1));
static Thread t2 = new Thread(new ThreadStart(Run2));
static NetworkStream ns = null;
static byte[] data1 = new byte[99999];
static byte[] data2 = new byte[99999];

static void Main(string[] args)
{
for (int i = 0; i < data1.Length; i++)
{
data1[i] = 1;
}
TcpClient client = new TcpClient("127.0.0.1", 8855);
ns = client.GetStream();
t1.Start();
t2.Start();
}

static void Run1()
{
int i=100;//无意义
ns.Write(data1, 0, data1.Length);
}
static void Run2()
{
int i=1000;//无意义
ns.Write(data2, 0, data2.Length);
}
}

大家有看到,Run1方法和Run2方法是在t1线程和t2线程中执行的
而且这2个线程是操作的同一个NetworkStream
我的问题是按照多线程的效果,Run1和Run2同时开始执行了。
他可能是执行Run1里面的int i=100。然后执行完了后就跳到Run2里面去执行Run2里面的int i=1000
当然也可能不跳,继续执行下面的一行代码,具体实际是怎样,得看cpu调度了。
我自己的代码,我知道我都写了哪些行代码,在交替执行的时候可能会执行哪些代码我都知道。
这一切都在我的掌控之中。
但是ns.Write这个方法不是我写的,是.Net Framework里面的方法,它的内部有哪些代码我也不知道。
我担心的是,在线程中调用.Net Framework里面类的方法的时候,这些方法内部肯定不止1行代码
所以这些方法内部的代码会不会也在交替着执行呢?
不知道我表述的问题有没有表述清楚,大家有没有理解。
我再换一个方式来阐述这个问题:
大家有看到我的ns.Write方法是分别往同一个网络流里面写字节数组。
data1字节数组里面包含的全部都是1,而data2字节数组里面包含的全部都是0.
Run1方法是在往字节流西面写入1
Run2方法是在往字节流里面写入0
这2个方法操作的是同一个网络流,并且同时在运行
因此,最终的结果这个网络流里面的数据是一下哪2种情况:
A:1111111.....111110000000......000000
B:0000000.....000001111111......111111
C:101110001110111110101010000111000011
如果是A或者B这2种情况的话,我就感觉线程是以我写的代码为准
一行代码完全执行完毕后才有可能跳入到其他线程中去执行代码
如果是C这种情况,就说明不是我写的代码也有可能会交替执行,而且它内部怎么交替我就不知道。
如果真是这样的情况,用多线程,我感觉好危险,必须要锁。

我有做过测试,我又写了一个程序,来读这个网络流,发现读出来的结果是A和B其中的1个,没有出现C的情况。
但是我也仅仅是测试了十几次,虽然没有出现C这种情况,我觉得有可能是我运气好,CPU调度的太完美。
所以发个帖子,征求大家的结论,希望能有个结果
拜求各位高人指点迷津。
...全文
344 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
windstore 2013-09-23
  • 打赏
  • 举报
回复
引用 5 楼 sp1234 的回复:
[Quote=引用 2 楼 的回复:] 嗯,我知道是分配时间片。 但是我想知道这个时间片内Run1里面的ns.Write方法还没执行完怎么办? 开始执行Run2里面的ns.Write吗? [/Quote] 是可以并行的!因为Write也是有一大堆操作,因此并行执行ns.Write是有一定的意义的。但是两个ns.Write并行执行,这并意味着数据就会乱。这就好像两个厨师可以分别给你炒一个菜,等菜上来时不会是两盘菜都成了大杂烩,因为它们的工作方式可以保证线程安全。
不知道仁兄是否真的测试过,经过我的测试,这个networkstream的read和write不是线程安全的。2个线程写的数据会搅在一起。networkstream本身就是一个流,2个线程同时写肯定会把一个流搞乱,只不过计算机允许的比较快,看不出来,多加个几个sleep,就看出效果了。
windstore 2013-09-23
  • 打赏
  • 举报
回复
[quote=引用 5 楼 sp1234 的回复:] [Quote=引用 2 楼 的回复:] 嗯,我知道是分配时间片。 但是我想知道这个时间片内Run1里面的ns.Write方法还没执行完怎么办? 开始执行Run2里面的ns.Write吗? [/Quote] 不知道仁兄是否真的测试过,经过我的测试,这个networkstream的read和write不是线程安全的。2个线程写的数据会搅在一起。networkstream本身就是一个流,2个线程同时写肯定会把一个流搞乱,只不过计算机允许的比较快,看不出来,多加个几个sleep,就看出效果了。
windstore 2013-09-23
  • 打赏
  • 举报
回复
引用 5 楼 sp1234 的回复:
[Quote=引用 2 楼 的回复:] 嗯,我知道是分配时间片。 但是我想知道这个时间片内Run1里面的ns.Write方法还没执行完怎么办? 开始执行Run2里面的ns.Write吗? [/Quote] 是可以并行的!因为Write也是有一大堆操作,因此并行执行ns.Write是有一定的意义的。但是两个ns.Write并行执行,这并意味着数据就会乱。这就好像两个厨师可以分别给你炒一个菜,等菜上来时不会是两盘菜都成了大杂烩,因为它们的工作方式可以保证线程安全。
不知道仁兄是否真的测试过,经过我的测试,这个networkstream的read和write不是线程安全的。2个线程写的数据会搅在一起。networkstream本身就是一个流,2个线程同时写肯定会把一个流搞乱,只不过计算机允许的比较快,看不出来,多加个几个sleep,就看出效果了。
SuperHero乐成 2012-10-15
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]

纠结于底层的一大堆技术辞藻解决不了实际问题。要从实际测试出发,然后再了解必要的技术辞藻。如果考虑过多概念,就成了杞人忧天,还不如少背点技术辞藻而多做一些测试,来的更实际。
[/Quote]
哈哈,大神说的有理。
我确实在写代码的过程中会有各种各样杞人忧天的问题。
其实我就是担心自己写出不稳定的代码影响以后程序的运行。
我觉得编程是一锤子的买卖,问题我希望自己尽最大可能的去避免。
我不喜欢发现后再解决,我喜欢在发生之前就要扼杀它在萌芽中。
因为我觉得有的问题不发生还好,一旦发生就可能是致命的。
自己一句简单的代码看似不是很高的风险,但是想想以后它在系统中运行,以及它可能遇到的问题。
风险还是很大的,比如银行系统等。
大神,我想请教您,您说ns.Write方法是线程安全的,我反编译了NetworkStream这个类。
发现Write方法内部有锁。
然后我觉得假如说我不是在网络通信这个领域。
我在其他的领域,.NetFramework类库里面那么多类,那么多方法。
我不可能说每一个都去反编译看他有没有lock吧。
我也不知道哪些是线程安全的,哪些不是。
那假如我有一天遇上不是线程安全的。怎么办?
会导致数据错乱吗?
我就是想知道这个线程,它具体内部是怎么在干?
望大神不吝赐教!!!
chichenzhe 2012-10-15
  • 打赏
  • 举报
回复
这个问题无非就是 write 方法是否线程安全的问题.
和本身 多线程 的探讨应该还扯不上什么关系.

并且由于socket 提供了异步BeginSend. 所以对 write 和 send 进行多线程操作也显得没有意义.

如果你要用多线程, 我觉得就 socket类型 而言的程序上, 应该用在 resv 之后的 消息处理过程上. 也就是你的业务逻辑上.

只要你的业务逻辑才是 更多需要考虑多线程的地方. socket 本身完全有一套异步解决方案
cheng2005 2012-10-15
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 的回复:]

引用 6 楼 的回复:

纠结于底层的一大堆技术辞藻解决不了实际问题。要从实际测试出发,然后再了解必要的技术辞藻。如果考虑过多概念,就成了杞人忧天,还不如少背点技术辞藻而多做一些测试,来的更实际。

哈哈,大神说的有理。
我确实在写代码的过程中会有各种各样杞人忧天的问题。
其实我就是担心自己写出不稳定的代码影响以后程序的运行。
我觉得编程是一锤子的买卖,问题我希望自己尽最大可能的……
[/Quote]
你早晚是累死的
SuperHero乐成 2012-10-15
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 的回复:]

引用 9 楼 的回复:

引用 6 楼 的回复:

纠结于底层的一大堆技术辞藻解决不了实际问题。要从实际测试出发,然后再了解必要的技术辞藻。如果考虑过多概念,就成了杞人忧天,还不如少背点技术辞藻而多做一些测试,来的更实际。

哈哈,大神说的有理。
我确实在写代码的过程中会有各种各样杞人忧天的问题。
其实我就是担心自己写出不稳定的代码影响以后程序的运行。
我觉得编程是一锤子的……
[/Quote]
哈哈,没关系,编程本来就累嘛,选择了,我就不怕累的。
只想学好它,写出完美的代码。
xuggzu 2012-10-14
  • 打赏
  • 举报
回复
还是上面说的,每个线程都有自己的栈,系统会自动保护线程中所有私有数据。
几个线程访问的变量如果是同一变量,只是读写它的先后顺序需要你来考虑并处理,这就用到了同步概念、
  • 打赏
  • 举报
回复
个ns.Write并行执行,这并意味着数据就会乱 --> 个ns.Write并行执行,这并非意味着数据就会乱
  • 打赏
  • 举报
回复
纠结于底层的一大堆技术辞藻解决不了实际问题。要从实际测试出发,然后再了解必要的技术辞藻。如果考虑过多概念,就成了杞人忧天,还不如少背点技术辞藻而多做一些测试,来的更实际。
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]
嗯,我知道是分配时间片。
但是我想知道这个时间片内Run1里面的ns.Write方法还没执行完怎么办?
开始执行Run2里面的ns.Write吗?
[/Quote]

是可以并行的!因为Write也是有一大堆操作,因此并行执行ns.Write是有一定的意义的。但是两个ns.Write并行执行,这并意味着数据就会乱。这就好像两个厨师可以分别给你炒一个菜,等菜上来时不会是两盘菜都成了大杂烩,因为它们的工作方式可以保证线程安全。
xuggzu 2012-10-14
  • 打赏
  • 举报
回复
没执完系统会把指令指针保存,给下次执行使用,一个线程给一个指令暂存(就是汇编中的IP),另外每个线程都有自己的栈,用于保存需要的寄存器值。
  • 打赏
  • 举报
回复
没有仔细看你后边一大堆问题,仅看了一下前边的代码(如果代码写的比一大堆啰嗦的注释清晰,那就好!):

ns.Write不会产生冲突,它是线程安全的,通讯的另一端可以保证连续收到data1然后是data2,或者连续收到data2然后收到data1,不会将数据打乱。
SuperHero乐成 2012-10-14
  • 打赏
  • 举报
回复
嗯,我知道是分配时间片。
但是我想知道这个时间片内Run1里面的ns.Write方法还没执行完怎么办?
开始执行Run2里面的ns.Write吗?
xuggzu 2012-10-14
  • 打赏
  • 举报
回复
多线程操作同一变量本来就危险,所以才出同步的概念。
cpU只是分配时间片,时间片到了还没执行完的话后面代的只能到下次时间片中继续执行.

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧