您的位置:首页 > 其它

.net多线程学习笔记1

2011-01-22 22:26 573 查看
1.什么是process和thread?

2.什么是appdomain?

3.什么是thread local storage及相关操作?

4.在.net framework中如何启动一个进程?

5.callbacks回调

6.参考资料和实验代码下载



1.了解.net framework下的process和thread

windows下通过启动任务管理器能够看到当前计算中正在运行的application应用程序的列表,如下图所示:





下图中显示了当前计算机中所有的进程信息:





上面的图片展示了下面一个事实,application中不止包含一个process,一个process可以包含几个thread,同时一个process中的所有进程thread共享操作系统分配给该进程的内存、时间片等资源,process和thread的关系如下图所示:







2.什么是appdomain?

2.1AppDomain简介

进程是存在独立的内存和资源的,但是AppDomain仅仅是逻辑上的一种抽象。一个process可以存在多个AppDomain,如下图所示:





2.2 存在了process之后为什么还需要使用AppDomain?

Since more than one AppDomain can exist in a process, we get some benefits. For example, until we had an AppDomain, processes that needed to access each other's data had to use a proxy, which introduced extra code and overhead. By using an AppDomain, it is possible to launch several applications within the same process. The same sort of isolation that exists with processes is also available for AppDomains. Threads can execute across application domains without the overhead of inter process communication. This is all encapsulated within the
AppDomain
class. Any time a namespace is loaded in an application, it is loaded into an AppDomain. The AppDomain used will be the same as the calling code unless otherwise specified. An AppDomain may or may not contain threads, which is different to processes.

"I have previously needed to execute code in a separate AppDomain for a Visual Studio add-in that used Reflection to look at the current project's DLL file. Without examining the DLL in a separate AppDomain, any changes to the project made by the developer would not show up in Reflection unless they restarted Visual Studio. This is exactly because of the reason pointed out by Marc: once an AppDomain loads an assembly, it can't be unloaded."

an AppDomain can be use to load an assembly dynamically, and the entire AppDomain can be destroyed without affecting the process. I think this illustrates the abstraction/isolation that an AppDomain gives us.简单的讲AppDomain提供了动态加载assembly能力

2.3.AppDomain简单使用示例

2.3.1设置并读取AppDomain中的数据

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AppDomainTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Fetching current Domain");
            //use current AppDomain, and store some data
            AppDomain domain = System.AppDomain.CurrentDomain;
            Console.WriteLine("Setting AppDomain Data");
            string name = "MyData";
            string value = "Some data to store";
            domain.SetData(name, value);
            Console.WriteLine("Fetching Domain Data");
            Console.WriteLine("The data found for key {0} is {1}",
                name, domain.GetData(name));
            Console.ReadLine();

        }
    }
}




2.3.2测试一个process中存在多个AppDomain,但是各个AppDomain中数据相互隔离的

static void Main(string[] args)
        {
            AppDomain domainA = AppDomain.CreateDomain("MyDomainA");
            AppDomain domainB = AppDomain.CreateDomain("MyDomainB");
            domainA.SetData("DomainKey", "Domain A value");
            domainB.SetData("DomainKey", "Domain B value");
            OutputCall();
            domainA.DoCallBack(OutputCall); //CrossAppDomainDelegate call
            domainB.DoCallBack(OutputCall); //CrossAppDomainDelegate call
            Console.ReadLine();
        }

        public static void OutputCall()
        {
            AppDomain domain = AppDomain.CurrentDomain;
            Console.WriteLine("the value {0} was found in {1}, running on thread Id {2}",
                domain.GetData("DomainKey"), domain.FriendlyName,
                Thread.CurrentThread.ManagedThreadId.ToString());
        }


3.什么是thread local storage及相关操作?

3.1thread local storage简介

cpu在一个时间点上只能执行一个程序,那么当一个程序的时间片到了之后,操作系统需要将这个程序换出,去执行另外的程序,那么这个将要被换出的程序在被移除cpu的使用权之前,需要将当前运行的信息保存起来,这就是tls的作用。在msdn中存在下面的对于tls的解释:



"Threads use a local store memory mechanism to store thread-specific data. The Common Language Runtime allocates a multi-slot data store array to each process when it is created. The thread can allocate a data slot in the data store, store and retrieve a data value in the slot, and free the slot for reuse after the thread expires. Data slots are unique per thread. No other thread (not even a child thread) can get that data.

If the named slot does not exist, a new slot is allocated. Named data slots are public, and can be manipulated by anyone."



3.2 相关操作

3.2.1 thread local storage数据存储隔离

using System;
using System.Threading;

namespace TLSDataSlot
{
    class Program
    {
        static void Main()
        {
            Thread[] newThreads = new Thread[4];
            for (int i = 0; i < newThreads.Length; i++)
            {
                newThreads[i] =
                    new Thread(new ThreadStart(Slot.SlotTest));
                newThreads[i].Start();
            }
        }
    }

    class Slot
    {
        static Random randomGenerator = new Random();

        public static void SlotTest()
        {
            // Set different data in each thread's data slot.
            Thread.SetData(
                Thread.GetNamedDataSlot("Random"),
                randomGenerator.Next(1, 200));

            // Write the data from each thread's data slot.
            Console.WriteLine("Data in thread_{0}'s data slot: {1,3}",
                AppDomain.GetCurrentThreadId().ToString(),
                Thread.GetData(
                Thread.GetNamedDataSlot("Random")).ToString());

            // Allow other threads time to execute SetData to show
            // that a thread's data slot is unique to the thread.
            Thread.Sleep(1000);

            Console.WriteLine("Data in thread_{0}'s data slot is still: {1,3}",
                AppDomain.GetCurrentThreadId().ToString(),
                Thread.GetData(
                Thread.GetNamedDataSlot("Random")).ToString());

            // Allow time for other threads to show their data,
            // then demonstrate that any code a thread executes
            // has access to the thread's named data slot.
            Thread.Sleep(1000);

            Other o = new Other();
            o.ShowSlotData();
            Console.ReadLine();
        }
    }

    public class Other
    {
        public void ShowSlotData()
        {
            // This method has no access to the data in the Slot
            // class, but when executed by a thread it can obtain
            // the thread's data from a named slot.
            Console.WriteLine(
                "Other code displays data in thread_{0}'s data slot: {1,3}",
                AppDomain.GetCurrentThreadId().ToString(),
                Thread.GetData(
                Thread.GetNamedDataSlot("Random")).ToString());
        }
    }
}




3.2.2使用ThreadStaticAttribute属性保证每个进程的数据唯一

using System;
using System.Threading;

namespace ThreadStatic
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 3; i++)
            {
                Thread newThread = new Thread(ThreadData.ThreadStaticDemo);
                newThread.Start();
            }
        }
    }

    class ThreadData
    {
        [ThreadStaticAttribute]
        static int threadSpecificData;

        public static void ThreadStaticDemo()
        {
            // Store the managed thread id for each thread in the static
            // variable.
            threadSpecificData = Thread.CurrentThread.ManagedThreadId;

            // Allow other threads time to execute the same code, to show
            // that the static data is unique to each thread.
            Thread.Sleep(1000);

            // Display the static data.
            Console.WriteLine("Data for managed thread {0}: {1}",
                Thread.CurrentThread.ManagedThreadId, threadSpecificData);
        }
    }
}








4.在.net framework中如何启动一个进程?

在.net framework中启动一个进程是比较简单,示例如下,分别是传递参数和不传递参数的情况:



不带参数:

Thread workerThread = new Thread(StartThread);
Console.WriteLine("Main Thread Id {0}",
    Thread.CurrentThread.ManagedThreadId.ToString());
workerThread.Start();

....
....
public static void StartThread()
{
    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine("Thread value {0} running on Thread Id {1}",
            i.ToString(), 
            Thread.CurrentThread.ManagedThreadId.ToString());
    }
}




带参数:

//using parameter
Thread workerThread2 = new Thread(ParameterizedStartThread);
// the answer to life the universe and everything, 42 obviously
workerThread2.Start(42); 
Console.ReadLine();

....
....
public static void ParameterizedStartThread(object value)
{
    Console.WriteLine("Thread passed value {0} running on Thread Id {1}",
        value.ToString(),
        Thread.CurrentThread.ManagedThreadId.ToString());
}


5.线程间的同步

这里使用一个timer来模拟线程之间的同步。



using System;
using System.Threading;

namespace CallBacks
{
    class Program
    {
        private string message;
        private static Timer timer;
        private static bool complete;

        static void Main(string[] args)
        {
            Program p = new Program();
            Thread workerThread = new Thread(p.DoSomeWork);
            workerThread.Start();

            //create timer with callback
            TimerCallback timerCallBack =
                new TimerCallback(p.GetState);
            timer = new Timer(timerCallBack, null, 
                TimeSpan.Zero, TimeSpan.FromSeconds(2));

            //wait for worker to complete
            do
            {
                //simply wait, do nothing
            } while (!complete);

            Console.WriteLine("exiting main thread");
            Console.ReadLine();
        }

        public void GetState(Object state)
        {
            //not done so return
            if (message == string.Empty) return;
            Console.WriteLine("Worker is {0}", message);
            //is other thread completed yet, if so signal main
            //thread to stop waiting
            if (message == "Completed")
            {
                timer.Dispose();
                complete = true;
            }
        }

        public void DoSomeWork()
        {
            message = "processing";
            //simulate doing some work
            Thread.Sleep(3000); 
            message = "Completed";
        }
    }
}








7.参考资料和实验代码下载

参考资料:

http://www.codeproject.com/KB/threads/ThreadingDotNet.aspx#Processes

http://msdn.microsoft.com/en-us/library/ms684841(v=vs.85).aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: