12篇学通C#网络编程——第一篇 基础之进程线程

       在C#的网络编程中,进程和线程是必备的基础知识,同时也是一个重点,所以我们要好好的掌握一下。

一:概念

          首先我们要知道什么是”进程”,什么是“线程”,好,查一下baike。

  进程:是一个具有一定独立功能的程序关于某个数据集合的一次活动。它是操作系统动态执行的基本单元,

           在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。

  线程:是"进程"中某个单一顺序的控制流。

  

关于这两个概念,大家稍微有个印象就行了,防止以后被面试官问到。

 

二:进程

       framework里面对“进程”的基本操作的封装还是蛮好的,能够满足我们实际开发中的基本应用。

 

<1> 获取进程信息

       framework中给我们获取进程的方式还是蛮多的,即可以按照Name获取,也可以按照ID获取,也可以获取本地和远程的进程信息。

public Process[] GetProcess(string ip = "")
        {
            if (string.IsNullOrEmpty(ip))
                return Process.GetProcesses();

            return Process.GetProcesses(ip);
        }
 Process process = Process.GetProcessById(Convert.ToInt32(processID));

<2> 启动和停止进程

  其实这个也没啥好说的,不过有一个注意点就是Process中的"kill"和"CloseMainWindow"的区别。

  windowMainWindow:  当我们打开的Process是一个有界面的应用程序时,推荐使用此方法,它相当于点击了应用程序的关闭按钮,是一个有序的

                                  终止应用程序的操作,而不像kill那么暴力。   

  kill:                         根据这个单词估计大家都知道啥意思吧,它的作用就是强制关闭我们打开的Process,往往会造成就是我们数据的丢失,所以

                                 说在万不得已的情况下不要使用kill,当然在无图形界面的应用程序中,kill是唯一能够结束Process的一个策略。

 

<3> 进程操作的一个演示

public class ProgessHelper
    {
        //主操作流程
        public static void MainProcess()
        {
            ProgessHelper helper = new ProgessHelper();

            var result = helper.GetProcess();

            helper.ShowProcess(result.Take(10).ToArray());

            Console.Write("\n请输入您要查看的进程:");

            helper.ShowProcessSingle(Console.ReadLine());

            Console.Write("\n请输入您要开启的程序:\t");

            var name = helper.StartProcess(Console.ReadLine());

            Console.WriteLine("程序已经开启,是否关闭?(0,1)");

            if (Console.ReadLine() == "1")
            {
                helper.StopProcess(name);

                Console.WriteLine("关闭成功。");
            }
        }

        #region 获取进程
        /// <summary>
/// 获取进程
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
        public Process[] GetProcess(string ip = "")
        {
            if (string.IsNullOrEmpty(ip))
                return Process.GetProcesses();

            return Process.GetProcesses(ip);
        }
        #endregion

        #region 查看进程
        /// <summary>
/// 查看进程
/// </summary>
/// <param name="process"></param>
        public void ShowProcess(Process[] process)
        {
            Console.WriteLine("进程ID\t进程名称\t物理内存\t\t启动时间\t文件名");

            foreach (var p in process)
            {
                try
                {
                    Console.WriteLine("{0}\t{1}\t{2}M\t\t{3}\t{4}", p.Id, p.ProcessName.Trim(), p.WorkingSet64 / 1024.0f / 1024.0f,
                                                                         p.StartTime, p.MainModule.FileName);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
        #endregion

        #region 根据ID查看指定的进程
        /// <summary>
/// 根据ID查看指定的进程
/// </summary>
/// <param name="processID"></param>
        public void ShowProcessSingle(string processID)
        {
            Process process = Process.GetProcessById(Convert.ToInt32(processID));

            Console.WriteLine("\n\n您要查看的进程详细信息如下:\n");

            try
            {
                var module = process.MainModule;

                Console.WriteLine("文件名:{0}\n版本{1}\n描叙{2}\n语言:{3}", module.FileName, module.FileVersionInfo.FileVersion,
                                                                           module.FileVersionInfo.FileDescription,
                                                                           module.FileVersionInfo.Language);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
        #endregion

        #region 进程开启
        /// <summary>
/// 进程开启
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
        public string StartProcess(string fileName)
        {
            Process process = new Process();

            process.StartInfo = new ProcessStartInfo(fileName);

            process.Start();

            return process.ProcessName;
        }
        #endregion

        #region 终止进程
        /// <summary>
/// 终止进程
/// </summary>
/// <param name="name"></param>
        public void StopProcess(string name)
        {
            var process = Process.GetProcessesByName(name).FirstOrDefault();

            try
            {
                process.CloseMainWindow();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
        #endregion
    }

 

快看,PPTV真的被我打开了,嗯,8错,Process还是蛮好玩的。

这里要注意一点:

      我们在59行中加上了Try Catch,这是因为每个Process都有一个MainModule属性,但并不是每一个MainModule都能被C#获取,

      如会出现如下的“拒绝访问”。

 

三: 线程

      同样线程的相关操作也已经被framework里面的Thread完美的封装,大大简化了我们的工作量,常用的操作如下

   <1> 启动线程。

   <2> 终止线程。

   <3> 暂停线程。

   <4> 合并线程。

             这个要解释一下,比如:t1线程在执行过程中需要等待t2执行完才能继续执行,此时我们就要将t2合并到t1中去,也就是在

          t1的代码块中写上t2.Join()即可。同样Join中也可以加上等待t2执行的时间,不管t2是否执行完毕。

 

   <5> 线程同步

            估计大家也知道,多线程解决了系统的吞吐量和响应时间,同时也给我们留下了比如死锁,资源争用等问题,那么我们如何

          解决这些问题呢?呵呵,Anders Hejlsberg 这位老前辈已经给我们提供了很多的实现同步线程的类,比如Mutex,Monitor,

          Interlocked和AutoResetEvent,当然在实际应用中,我们还是喜欢使用简化版的lock,因为这玩意能够使编程简化,同时使

         程序看起来简洁明了。 

 

 <6>  同样我也举个例子

 

public class ThreadHelper
    {
        public static void MainThread()
        {

            ThreadHelper helper = new ThreadHelper(100);

            Thread[] thread = new Thread[20];

            for (int i = 0; i < 20; i++)
            {
                thread[i] = new Thread(helper.DoTransactions);

                thread[i].Name = "线程" + i;

            }

            foreach (var single in thread)
            {
                single.Start();
            }
        }

        int balance;

        object obj = new object();

        public ThreadHelper(int balance)
        {
            this.balance = balance;
        }

        #region 取款操作
        /// <summary>
/// 取款操作
/// </summary>
/// <param name="amount"></param>
        public void WithDraw(int amount)
        {
            lock (obj)
            {
                if (balance <= 0)
                {
                    Console.WriteLine("哈哈,已经取完了");
                    return;
                }

                if (balance >= amount)
                {
                    Console.WriteLine("取款前余额:{0},取款:{1},还剩余额:{2}", balance, amount, balance - amount);
                    balance = balance - amount;
                }
                else
                {
                    Console.WriteLine("取款前余额:{0},取款:{1},还剩余额:{2}", balance, balance, balance = 0);
                }
            }
        }
        #endregion

        #region 自动取款操作
        /// <summary>
/// 自动取款操作
/// </summary>
        public void DoTransactions(object obj)
        {
            int random = new Random().Next(4, 10);

            Thread.Sleep(5000);

            WithDraw(random);
        }
        #endregion
    }

 

当我们加上lock的时候一切正常,但是当我们把lock去掉的时候,看看线程们会有“争用资源”的现象吗?,在下图中可以看到,出现了如下的现象,

当然这不是我想看到的结果,如果在实际应用中会是多么难找的bug。

 

<8> 线程池

     上面的例子中,我创建了20个线程来完成任务,比如在某些实际应用中,Client端的每个请求Server都需要创建一个线程来处理,

     那么当线程很多的时候并不是一件好事情,这会导致过度的使用系统资源而耗尽内存,那么自然就会引入“线程池”。

     线程池:是一个在后台执行多个任务的集合,他封装了我们对线程的基本操作,我们能做的就只要把“入口方法”丢给线程池就行了。

     特点:  线程池有最大线程数限制,大小在不同的机器上是否区别的,当池中的线程都是繁忙状态,后入的方法就会排队,直至池中有空闲

               的线程来处理。

     代码: 修改后如下

public static void MainThread()
        {

            ThreadHelper helper = new ThreadHelper(100);

            for (int i = 0; i < 20; i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(helper.DoTransactions));
            }

            //Thread[] thread = new Thread[20];

//for (int i = 0; i < 20; i++)
//{
//    thread[i] = new Thread(helper.DoTransactions);

//    thread[i].Name = "线程" + i;

//}

//foreach (var single in thread)
//{
//    single.Start();
//}
        }
时间: 2024-11-01 09:37:00

12篇学通C#网络编程——第一篇 基础之进程线程的相关文章

12篇学通C#网络编程——第三篇 HTTP应用编程(下)

    第三篇来的好晚啊,上一篇说了如何向服务器推送信息,这一篇我们看看如何"快好准"的从服务器下拉信息.     网络上有很多大资源文件,比如供人下载的zip包,电影(你懂的),那么我们如何快速的进行下载,大家第一反应肯定就是多线程下载, 那么这些东西是如何做的呢?首先我们可以从"QQ的中转站里面拉一个rar下来". 然后用fiddler监视一下,我们会发现一个有趣的现象: 第一:7.62*1024*1024≈7990914  千真万确是此文件 第二:我明明是一个

12篇学通C#网络编程——第四篇 TCP应用编程

 年底了,人浮躁多了,沉不下去心研究技术了,不过昨天终于抢到了回家的票,很开心.     言归正卷,在WCF出来之后,可能我们玩这些原始的TCP越来越少了,我们知道WCF对TCP进行了再一次的包装,第一反应给我们的或许是 同构系统用TCP,异构系统用HTTP,那么问题来了,异构系统到底可不可以用TCP呢?至少WCF是玩不了的,因为其他语言没有针对.net的"服务 引用",也没有什么ChannelFactory给你去玩,如果你是一定要追求性能的话,原始的TCP会助你一臂之力的.    我

大话“网络营销”第一篇:做好网站产品及服务的构架

&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp;      近日来一觉醒来,"营销专家"如雨后春笋,建了个网站,打了个旗号,写了几篇文章,出版了本营销手册.就自以为是"营销专家"了. 何谓营销,众口纷纭,'营销专家'仿佛拯救了中国互联网,仿佛拯救了危难中的中小企业.满口的搜索引擎,关键字推广,SEO和所谓的竞价排名. 营:经营,销:销售        经营代表了产品的生产加工

想学vb.net网络编程,给推荐本书吧。最好是pdf的

问题描述 如题主要是想做C/s开发. 解决方案 解决方案二:到这里问都不如自己搜一下.网上很多.自己多年前买过一本.

Unix网络编程 之 socket基础

基本结构 (这部分的地址均为网络地址<网络字节序>) 1.struct sockaddr:通用套接字地址结构     此结构用于存储通用套接字地址.    数据结构定义: typedef unsigned short sa_family_t; struct sockaddr { sa_family_t sa_family; /* address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */ };  

linux网络编程之进程间通信基础(二) 死锁、信号量与PV原语简介

一.死锁 (1) 死锁是指多个进程之间相互等待对方的资源,而在得到对方资源之前又不释放自己的资源,这样 ,造成循环等待的一种现象.如果所有进程都在等待一个不可能发生的事,则进程就死锁了. (2)死锁产生的必要 条件: 互斥条件 进程对资源进行排它性使用,即在一段时间内某资源仅为一个进程所占用. 请求和保持条件 当进程因请求资源而阻塞时,对已获得的资源保持不放. 不可剥夺条件 进程已获得的资源在未使用完之前,不能被剥夺,只能在使用完时由自己释放. 环路等待条件 各个进程组成封闭的环形链,每个进程都

linux网络编程之进程间通信基础(一) 进程间通信概述

一.顺序程序与并发程序特征 顺序程序特征 顺序性 封闭性:(运行环境的封闭性) 确定性 可再现性 并发程序特征 共享性 并发性 随机性 二.进程互斥 1.由于各进程要求共享资源,而且有些资源需要互斥使用,因 此各进程间竞争使用这些资源,进程的这种关系为进程的互斥 2.系统中某些资源一次只允许一个进程使用,称这样的资 源为临界资源或互斥资源. 3.在进程中涉及到互斥资源的程序段叫临界区 举例如下图: 假设x = 1; 当A进程已经判断完毕x>0,此时时间片轮转到了B,B也判断x>0,然后执行x-

Linux网络编程一步一步学【转】

转自:http://blog.chinaunix.net/uid-10747583-id-297982.html Linux网络编程一步一步学+基础  原文地址:http://blogold.chinaunix.net/u1/48325/showart_413841.html ·Linux网络编程基础(一)·Linux网络编程基础(二)·Linux网络编程基础(三) • Linux网络编程一步一步学-简单客户端编写   • Linux网络编程一步一步学-绑定IP和端口 • Linux网络编程一步

C#网络编程(基本概念和操作)

引言 C#网络编程系列文章计划简单地讲述网络编程方面的基础知识,由于本人在这方面功力有限,所以只 能提供一些初步的入门知识,希望能对刚开始学习的朋友提供一些帮助.如果想要更加深入的内容,可以 参考相关书籍. 本文是该系列第一篇,主要讲述了基于套接字(Socket)进行网络编程的基本概念,其中包括TCP协议 .套接字.聊天程序的三种开发模式,以及两个基本操作:侦听端口.连接远程服务端:第二篇讲述了一 个简单的范例:从客户端传输字符串到服务端,服务端接收并打印字符串,将字符串改为大写,然后再将 字符