GSI

사용자 삽입 이미지

DirectX 코드를 사용해서 텍스처를 연결시켰다.
기존 코드 : http://www.iamgsi.com/entry/DirecrX-Managed-Create-a-Device-C
를 조금더 확장 시켰다.
이벤트 함수 OnResetDevice도 추가 했으며,
여기서 봐야 할 것은 윈도우 사이즈가 변할때 텍스처가 검정색으로 나올때가 있다.
이때 텍스처 함수 부분은 Managed로 해야 하는지는 잘 모르겠지만.
아래와 같은 인자를 사용하게 되는데 Managed를 할때는 몇개의 인자가 더 필요 하더라.

아래의 함수를 사이즈 변할때 호출해줘야 제대로 나오게 된다.
private void directXBaseView1_OnResetDevice(object sender, DeviceEventArgs e)
{
     ...
    if (texture != null)
        texture.Dispose();  // 이 코드를 넣지 않으면 메모리가 계속 누적된다. Texture가 계속해서 생성이 되는거 같다.
    texture = TextureLoader.FromFile(dev, @"d:\bbbb.jpg");
}

나머지는 타이머를 사용해서 화면은 계속해서 리프레쉬 해주었다.

Posted by gsi
:

사용자 삽입 이미지

C#에서 프로젝트를 하기 위해서 DirectX를 연동하고 있다.
현재 소스는 Tutorial 1: Create a Device를 사용해서 UserControl에 붙인 것과 동일합니다.

Posted by gsi
:

csFile 클래스 래퍼 클래스

C# 2007. 10. 19. 15:45 |

csFile 클래스
때로는 사용하기 쉬운 메서드를 제공하는 간단한 클래스를 만들고, 그 안에서 이들 파일과 관련된 메서드들을 감싸두면( Wrap ) 편리하다. 그러므로 여기서는 그러한 csFile 클래스를 작성하고, 나머지 장들의 예제에서 이 클래스를 사용해 볼 것이다.

public class csFile {
   private string fileName;
   StreamReader ts;
   StreamWrite ws;

   private bool opened, writeOpened;

   //--------------
   public csFile() { Init(); }

   //--------------
   private void Init() {
      opened = false;
      writeOpened = false;
   }

   //---------------
   public csFile(string file_name) {
      fileName = file_name;
      Init();
   }
}

우리는 두 가지 방법으로 파일을 읽기 위해 열 수 있다. 하나는 파일 이름을 포함하는 것이고, 다른 하나는 파일 이름을 인수로 받는 것이다.

그리고 readLine 메서드를 이용하여 텍스트 파일로 부터 데이터를 읽어 올 수 있다.

public bool OpenForRead(string file_name)
{
   fileName = file_name;
   try {
      ts = new StreamReader(fileName);
      opened = true;
   }
   catch(FileNotFoundException e) {
      return false;
   }
   return true;
}

//-----------------
public bool OpenForRead() {
   return OpenForRead(fileName);
}
public string readLine() {
   return ts.ReadLine();
}

마찬가지로, 다음 메서드는 파일에 쓸 수 있게 해준다.

public void writeLine(string s) {
   ws.WriteLine(s);
}
//------------
public bool OpenForWrite() {
   return OpenForWrite(fileName);
}
//------------
public bool OpenForWrite(string file_name) {
   trye {
      ws = new StreamWriter(file_name);
      fileName = file_name;
      writeOpended - true;
      return true;
   }
   catch(FileNotFoundException e) {
      return false;
   }
}

앞으로 파일 읽어야 할 때 이렇게 단순화된 파일 메서드 래퍼 클래스를 사용하면 좋다.

Posted by gsi
:

파일 끝을 검사하기

C# 2007. 10. 19. 15:44 |

파일 끝을 검사하기
파일의 끝을 지났는지 확인하는 방법에는 두 가지가 있다. 즉, null 예외를 찾는 것과 데이터 스트림의 끝을 찾는 것이다. 실제로, 텍스트 파일의 끝을 지나서 파일을 읽더라도 아무런 에러도 발생하지 않고, 파일 끝 예외도 발생하지 않는다. 그러나 파일의 끝을 지나서 읽으려고 한다면, null 값을 반환받게 될 것이다. 그러므로 이것을 이용하여 파일을 읽는 클래스에서 파일 끝을 검사하는 기능을 만들 수 있다.

private StreamReader rf;
private bool eof;
//--------------
public String readLine() {
   String s = rf.ReadLine();
   if( s == null )
      eof = true;
}
//---------------
public bool fEof {
  return eof;
}

파일의 끝을 지나서 읽는 것을 막기 위한 또 다른 방법은 Stream 객체의 Peek 메서드를 사용하여 미리 값을 꺼내 오는 것이다. 이것은 남은 문자가 있으면 다음 문자의 아스키 코드 값을 반환하고, 남아 있는 문자가 없으면 -1을 반환한다.

public String read_Line() {
   String s = "";
   if(rf.Peek() > 0) {
      s = rf.ReadLine();
   } else {
      eof = true;
   }
   return s;
}
Posted by gsi
:

파일 내에서의 예외 처리

C# 2007. 10. 19. 15:44 |

파일 내에서의 예외 처리
자주 발생하는 많은 예외는 파일의 입출력이 일어날 때 생긴다. 주로 유효하지 않은 파일 이름, 존재하지 않는 파일, 존재하지 않는 디렉토리, 유효하지 않은 파일 이름 인수, 파일 접근 권한 에러 등의 예외를 접할 수 있다. 따라서 파일의 입출력을 처리하는 가장 좋은 방법은, 파일을 처리 하는 코드를 try  불록에 넣고 가능한 모든 에러 조건을 잡아서 당황스럽고 치명적인 에러를 방지하는 것이다. 다양한 파일 클래스의 메서드에서 발생할 수 있는 모든 예외는 문서에 나타나 있다. 그리고 확실하게 모든 예외를 잡아내고 싶으면 일반적인 Exception 객체에 대한 처리를 하면 된다. 그러나 각각의 예외에 대해 다른 처리를 하고 싶다면, 예외에 따라 분리해서 검사할 수 있다.

try {
   // 텍스트 파일을 읽기 위해 연다.
   StreamReader ts = File.OpenText("fool.txt");
   String s = ts.ReadLine();
}
catch (Exception e) {
   Console.WriteList(e.Message);
}
Posted by gsi
:

파일 처리 (File Handling)

C# 2007. 10. 19. 15:42 |

C# 에서 파일을 처리하는 객체는 파일을 유연하게 사용하는 방법을 제공한다.

File 객체
File 객체는 파일을 나타내며, 파일의 존재를 검사하고, 이름을 바꾸고, 지우는 등의 기능을 하는 유용한 메서드 들을 제공한다. 모든 메서드는 static이므로 이들 메서드를 사용하기 위해 File 클래스의 인스턴스를 생성할 필요는 없다. 그 대신, 메서드를 직접 사용하면 된다.

fi(File.Exists("Foo.txt"))
   File.Delete("Foo.txt");

File을 사용하여 파일을 읽고 쓰는데 필요한 FileStream을 구할 수도 있다.

//텍스트 파일을 읽기 위해 파일을 연다.
StreamReader ts = File.OpenText("fool.txt");
//임의의 타입의 파일을 읽기 위해  파일을 연다.
FileStream fs = File.OpenRead("foo2.any");

File  클래스의 메서드들...

  • File.FileExists(filename) : 파일이 존재한다면 true를 반환함
  • File.Delete(filename) : 파일 삭제
  • File.AppendText(fliename) : 텍스트를 덧붙임
  • File.Copy(filename) : 파일 복사
  • File.Move(filename) : 파일 이동 후 이전 파일은 삭제
  • File.GetExtension(filename) : 파일 확장자를 반환함
  • File.HasExtension(filename) : 파일이 확장자를 갖고 있다면 true를 반환함

텍스트 파일 읽기
텍스트 파일 읽기 위해서는, File 객체를 이용하여 StreamReader 객체를 얻어내야 한다. 그 다음에는 텍스트 스트림을 읽는 메서드를 사용하면 된다.

StreamReader ts = File.OpenText("fool.txt");
String s = ts.ReadLine();

텍스트 파일 쓰기
텍스트 파일을 만들고 쓰기 위해서는, CreateText 메서드를 사용하여 StreamWriter를 얻어낸다.

//쓰기 위해 열기
StreamWriter sw = File.CreateText("Foo3.txt");
sw.WriteLine("Hello file");

만약 이미 존재하는 파일에 덧붙이기를 원한다면, 파일 이름 다음에 오는 Boolean 인수를 true로 지정하여 직접 StreamWriter 객체를 생성할 수도 있다.

//텍스프 파일에 덧붙이기
StreamWriter asw = new StreamSwiter("fool.txt", true);
Posted by gsi
:

Exception (예외) 처리

C# 2007. 10. 19. 15:17 |

Exception

C# 에서의 에러 처리는 예외를 사용하여 손쉽게 수행된다. 예외 처리는 에러가 발생할 만한 구문들을 try 블록 안에 넣고, catch 블록에서 에러를 잡는 것이다.

try {
   // 에러가 발생할 만한 구문
}
catch (Exception e) {
   // 에러가 발생했을 때 처리하는 구문
}
finally {
   // 언제나 실행되는 구문
}


이러한 접근 방식은 파일을 다루는 문장에서 에러를 검사하거나, 배열의 범위를 벗어나는 인덱스 문장의 에러를 잡아내는 등의 여러가지 에러 상황을 검사하는 곳에서 사용된다. 이 방법이 동작하는 방식은 일단 try 블록이 실행되고, 여기서 에러가 발생하지 않으면, finally 블록이 실행된다. 만약 try 구문내에서 에러가 발생하면 제어가 catch 구문으로 넘어간 후, finally 블록을 실행하고 밖으로 빠져나가게 된다.

다음 예제는 예외를 검사하는 것을 보여준다. ArrayList 에서 범위를 벗어난 값에 접귾려고 했기 때문에, 에러가 발생할 것이다.

try {
   // 너무 많이 접근한다는 점에 주의 하자
   for(int i = 0; i <= arl.Count; i++)
      console.WriteList(arl[i]);
}
catch (Exception e) {
   Console.WriteList(e.Message);
}


이 코드는 에러 메시지를 출력하고, 프로그램에서 에러가 발생한 부분을 보여주고 계속 실행된다.

0123456789 인덱스가 범위를 벗어났습니다.
인덱스는 음수가 아니어야 하며 컬렉션의 크기보다 작아야 합니다.
매개 변수 이름 : index
   at System.Collections.Arraylist.get_Item(int32 index)
   at arr.Form1..ctor() in form1.cs:line 58

만약 예외를 잡아내지 못하면, 실행중에 시스템으로부터 에러 메시지를 받고, 프로그램은 계속 진행되지 않고 종료될 것이다.

C# 예외 클래스들..

  • AccessException : 클래스의 메서드 또는 필드에 접근할 때의 에러
  • ArgumentException : 메서드의 인수가 유효하지 않음
  • ArgumentNullException : 인수가 null임
  • ArthmeticException : 오버플로우 또는 언더플로우
  • DivideByZeroException : 0으로 나누기
  • IndexOutOfRangeException :배열의 범위를 넘어선 인덱스
  • FileNotFoundException : 파일을 찾을수 없음
  • EndOfStreamException : 입력 스트림의 범위를 넘어선 접근
  • DirectoryNotFoundException : 디렉터리를 찾을 수 없음
  • NullReferenceException : 객체 변수가 실제값으로 초기화 되지 않음

다중 예외
여러 개의 catch 블록에서 여러 개의 예외를 받아 서로 다르게 처리할 수 있다.

try {
   for(int i = 0; i <= arl.Count; i++) {
      int k = (int)(float)arl[i];
      Console.Write(i + "" + k/i);
   }
   catch (DivideByZeroException e) {
      printZErr(e);
   }
   catch (IndexOutOfRangeException e) {
      printOErr(e);
   }
   catch(Exception e) {
      printErr(e);
   }
}


예외 던지기
예외가 발생했다고 해서 바로 그곳에서 처리해야할 필요는 없다. throw 구문을 사용하여 호출한 프로그램에게 예외를 전달할 수 있다. 이것은 호출한 프로그램에서 예외가 발행하게 하는 것이다.

try {
   // 구문
}
catch (Exception e) {
   throw(e);      // 호출한 프로그램에게 전달한다.
}

C#은 자바의 throw 구문을 지원하지 않는다는 것에 주의 하자. 자바에서는 메서드가 예뢰를 던질 것이라는 것을 선언할 수 있으므로, 프로그램에서는 반드시 예외 처리 핸들러를 제공해야 한다.

Posted by gsi
:

Collection 객체

C# 2007. 10. 19. 14:38 |

System.Collections 네임 스페이스에는 여러가지 방법으로 항목을 추가하거나 구할 수 있는 가변 길이의 배열 객체들이 많이 있다.

ArrayList
ArrayList 객체는 필요할 때마다 항목을 추가할 수 있는 가변 길이의 배열로, ArrayList의 기본적인 메서드를 사용하면 쉽게 배열에 요소를 추가하고, 개별 요소를 변경시킬 수 있다.

float[] z = {1.0f, 2.9f, 5.6f};
ArrayList arl = new ArrayList();
for(int j = 0; j < zLength; j++)
{
   arl.Add(z[j]);
}

ArrayList는 배열의 개수를 찾느 데 사용할 수 있는 Count 속성을 갖고 있다. ArrayList를 배열과 같이 취급하여, 0에서 시작하여 Count 속성 값보다 하나 작은 값까지 이동하면서 이들 요소에 접근 할 수 있다.

for(j = 0; j < arl.Count; j++)
{
   Console.WriteList(arl[j]);
}

또한 foreach 루프 구문을 사용하여 인덱스 변수를 생성하거나, ArrayList의 길이를 알지 못하고도  ArrayList 객체의 멤버에 순차적으로 접근 할 수 있다.

foreach(float a in arl)
{
   Console.WriteList(a);
}

ArrayList에서 가져온 객체는 항상 object 타입이다. 따라서 우리는 그것을 사용하기 전에 반드시 정확한 타입으로 변환해야 한다.

float x = (float)arl[j];

ArrayList 메서드

  • Clear :  ArrayList 안에 있는 모든 내용을 삭제한다.
  • Contains(object) : ArrayList가 해당하는 값을 가지고 있으면 true를 반환한다.
  • CopyTo(array) : ArrayList의 모든 내용을 일차원 배열에 복사한다.
  • IndexOf(object) : 해당하는 값의 첫번째 인덱스를 반환한다.
  • Insert(index, object) : 정해진 인덱스에 요소를 삽입힌다.
  • Remove(object) : 목록에서 지정된 객체를 삭제한다.
  • RemoveAt(index) : 지정된 위치에서 요소를 삭제한다.
  • Sort : ArrayList를 정렬한다.


HashTable

HashTable은 각각의 요소들을 키 값으로 접근할 수 있는 가변 길이의 배열이다. 일반적으로 키 값은 문자열로 지정하지만, 어떤 객체로 지정해도 상관이 없다. 각각의 요소는 중복되는 값이 있어도 상관없지만, 그 키 값은 반드시 유일해야 한다. HashTable은 크고 정렬되지 않은 항목들의 집합에 빠르게 접근하는 데 사용되고, 키와 요소의 값을 역순으로 함으로써 요소가 중복되지 않는 것을 보장하기 위해 사용되기도 한다.

HashTable hash = new HashTable();
float freddy = 12.3f;
hash.Add("fread", freddy);
float tmp = (float)hash["fread"];

ArrayList 에서와 같이 HashTable에서 구한 갑도 만드시 적절한 타입으로 변환해서 사용해야 한다. 또한, HashTable도 Count 속성을 가지고 있으므로 클래스의 키 또는 값들의 개수를 알아낼 수 있다.

SortedList
SortedList 클래스는 두 개의 내부 배열을 관리하며, 0부터 시작하는 인덱스와 알파벳 키 중 하나를 사용하여 요소를 구할 수 있다.

float sammy = 44.5f;
ShortedList slist = new SortedList();
slist.Add("fred", freddy);
slist.Add("sam", sammy);
float newFred = (float)slist.GetByIndex(0);
float newSam = (float)slist["sam"];
Posted by gsi
:

delegate (위임) 사용법

C# 2007. 10. 19. 13:49 |

Delegate 사용법

C#은 C언어에는 없는 위임이라는 독특한 특징을 도입했다. 기본적으로 위임이란, 같은 인터페이스를 만족시키는 한, 어느 클래스로부터 홨는지알지 못하더라도 넘겨주고 사용할 수 있는 다른 클래스에 있는 함수의 참조이다.

사용자 삽입 이미지

심플 예제

위의 화면에서 보는것과 같이 위쪽에 TextBox에 입력한 문자열을 Process를 누르게 되면
대문자 또는 소문자를 자동으로 만들어 주는 기능을 한다.
이때 Capital, Lower를 체크 해주게 되는데
내부적인 코드는 아래와 같다.

namespace WindowsFormsApplication4
{
    public partial class Form1 : Form
    {
        private delegate string fTxDelegate(string s);
        fTxDelegate ftx;

        public Form1()
        {
            InitializeComponent();
        }

        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            button1.Enabled = true;

            ftx = new fTxDelegate(new Capital().fixText);
        }

        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            button1.Enabled = true;

            ftx = new fTxDelegate(new Lower().fixText);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            listBox1.Items.Add(ftx(textBox1.Text));
        }
    }

    public class Capital
   {
        public string fixText(string s) {
            return s.ToUpper();
        }
    }

    public class Lower
   {
        public string fixText(string s) {
            return s.ToLower();
        }
    }
}

fix 메서드는 어떤 fixText를 호출할지를 자동으로 결정해 준다.

Posted by gsi
:

C# 기초 - 배열

C# 2007. 10. 15. 16:47 |

배열
정수형 배열은 아래와 같이 선언
int [] array;

배열 선언시 몇개의 요소를 가질것인지 선언해야 한다.
5개의 값을 갖는 배열을 선언
int [] array = new int[5];
array[0] = 100;
int value = array[0];

배열의 크기는 array.Length로 구할 수 있습니다.
반복문을 사용할 때 유용합니다.
for(int i = 0; i < array.Length; i++) {
   array[i] = i * 100;
   ...
}

배열 초기화
int [] array = { 1, 2, 3, 4, 5 };

int [] array;
array = new int [] { 1, 2, 3, 4, 5 };
array = { 1, 2, 3, 4, 5 }; //이렇게는 사용할 수 없습니다.

string [] sarray = { "first", "second", "third" };

//값을 나중에 초기화한 경우
string [] sarray;
sarray = new string [] { "first", "srcond", "third" };

Array 객체
C# 언어에서 배열은 고유한 데이터형입니다. Array 객체는 배열에서 사용할 수 있는 다양한 메시드와 멤버를 제공합니다.

int value = Array.Length; //배열의 길이를 리턴합니다.
Array.Sort( arr ); // 배열에 있는 요소 값을 정렬합니다.
Array.Reverse( arra ); //배열에 요소 값을 거꾸로 배치합니다.
int index = Array.IndexOf( arr, Value ); //배열의 처음부터 값을 찾기 시작해서 맨 처음 찾은 값의 위치를 알려 줍니다.
int index = Array.LastIndexOf( arr, value ); //배열의 끝에서 부터 거꾸로 찾아서 위치를 알려 줍니다.
int index = Array.BinarySearch( arr, value ); //배열에서 Binary search를 수행합니다.

foreach 문
for문을 이용해서 배열 값을 보일수도 있고, foreach 문을 이용할 수도 있습니다. foreach문은 배열의 처음부터 순서대로 값을 보여줍니다. 인덱스 값을 따로 지정할 필요가 없습니다.
foreach ( string str in arr )
{
   Response.Write (str );
}

다차원 배열

int [,] array; // 2차원 배열 선언
array = new int [3, 3];
int [,,] array; // 3차원 배열 선언

array [1, 2] = 100; //2행 3렬에 값 넣기

다차원 배열 초기화
배열을 선언하면서 바로 요소 값을 초기화할 수도 있습니다. 값을 정의하는 각 열마다 {,}를 이용해서 구분해 줍니다. 다음 두 문장은 같은 배열을 선언하는 코드입니다. new int [,]은 마찬가지로 생략할 수 있습니다.

int [,] array = new int [,] { {1, 2, 3}, {4, 5, 6} };
int [,] array = { {1, 2, 3}, {4, 5, 6} };


Posted by gsi
:

C# 기초 - 기본 데이터형

C# 2007. 10. 15. 16:29 |

기본 데이터형
C# 언어에서 제공하는 기본 데이터형은 값 형과 레퍼런스 형으로 나눌 수 있습니다. object 형과 string형은 레퍼런스(reference)형이고 나머지 기본 데이터형은 모두 값(value)입니다.

▶ 정수형과 실수형
▶ 논리형과 문자형
▶ object 형과 string 형

정수형

sbyte : 8비트 : -128 ~ 127
byte : 8비트 : 0 ~ 255
short : 16비트 : -32,768 ~ 32,767
ushort : 16비트 : 0 ~ 65,535
int : 32비트
uint : 32비트
long : 64비트  (ex : long l = 200L; )
ulong : 64비트 (ex : ulong ul = 300UL; )

실수형
float : 7 digits (ex : float f = 123.45F; )
double : 5 digits (ex : double d = 123.45D; )

Decimal 형
decimal 형은 실수형보다 더 큰 숫자를 다룰 때 사용합니다.

decimal : 128비트 (ex : decimal x = 12.345M; )

논리형
true 또는 false를 갖는 변수

문자형

문자를 표현하는 데이터 형입니다. 16비트 크기를 가지며 유니코드(Unicode) 형태로 문자를 다룹니다.

char c1 = 'x';              // 문자 'x'
char c2 = '\x0058';     // 16진수 값
char c3 = (char)88;     // 정수 값을 문자형으로 변환
char c4 = '\u0058';    // 유니코드

object  형

모든 C#의 데이터 형은 object을 상속받아 정의된 것이다.

object obj = 1234;
object obj = "C# programming";

string 형

문자열을 다루는 데이터 형입니다.

string name = "C# Programming";

enum 형
이넘(enum)은 정수형 상수를 정의할 때 사용합니다.

public enum Color {Red, Green, Blue };

Posted by gsi
:

발췌...(inside C#_2E, 무료기술 서적)

FileStream은 바이너리 데이터를 읽거나 쓸 수 있다. 문자 데이터로 작업하려면 StreamReader와 StreamWrite와 같은 클래스가 더 적합하다. 이러한 클래스는 백그라운드에서 FileStream 객체를 사용하여 원본 바이트 처리 과정의 최상위 계층인 문자 삽입 계층에 효과적으로 작동할 것이다. StreamReader/StreamWriter를 닫는 것은 백그라운드에 깔려 있는 FileStream 또한 닫는다는 것을 의미한다.

FileStream s =
    new FileStream("Bar.txt", FileMode.Create);
StreamWriter w = new StreamWriter(s);
w.Write("Hello World");
w.Close();

s = new FileStream("Bar.txt", FileMode.Open);
StreamReader r = new StreamReader(s);
string t;
while ((t = r.ReadLine()) != null)
{
    Console.WriteLine(t);
}
w.Close()

결과 : Hello World

StreamReader 클래스와 StreamWriter 클래스는 Encoding을 사용하여 문자를 바이트로 혹은 그 반대로 변환할 수 있다. 몇몇 엔코딩을 이용하여 데이터를 파일에 기록하려면 다음과 같이 StreamWriter와 Encoding 파라미터를 추가한 StreamReader를 생성해야 한다.

//StreamWriter w = new StreamWriter(s);
StreamWriter w = new StreamWriter(s, System.Text.Encoding.BigEndianUnicode);

[참고]
읽기 전용으로 설정된 파일을 열려면 FileStream 생성자에 파일을 읽기만 하도록 지정하기 위해 몇가지의 파라미터를 더 추가할 수 있다.

s = new FileStream(
   "../../TextFile1.txt",
   FileMode.Open, FileAccess.Read);

[참고]
C#에서 파일 경로를 지정할 때 C#에서의 경로는 C나 C++와 동일하게 백슬래시(\)를 사용하기 때문에, 다음과 같은 3가지 방법 중 선택해서 사용할 수 있다.

s = new FileStream(
   "C:\\temp\\goo.txt", FileMode.Create);
or.
s = new FileStream(
   "C:/temp/goo.txt, FileMode.Create);
or.
s = new FileStream(
   @"C:\temp\goo.txt", FileMode.Create);

이상....

Posted by gsi
:

Thread를 두개를 사용할 경우 하나의 함수를 호출한다고 가정해 보자.
그렇게 되면 다량의 데이터를 효과적으로 여러개의 스레드를 사용해서 처리할 수가 있다.
아래의 예제를 보면 AddItems()를 스레드 두개를 사용해서 처리 되고 있다.
하지만 결과를 보면 100개의 데이터 값만 뿌려지는 것을 알수 있다.

이때 사용하게 되는 것이 lock 구문이다. 이 구문을 사용해서 멀티 스레드에서의
데이터를 안전하게 처리할 수 있다.
lock 에 포함되는 것은 동기화에 처리되어야 할 데이터를 락을 걸어 주게 되는 것으로
여겨진다.

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace ConsoleApplication4
{
    class Program
    {
        static List<string> list = new List<string>();

        static void Main(string[] args)
        {
            new Thread(AddItems).Start();
            new Thread(AddItems).Start();
        }

        static void AddItems()
        {
            for (int i = 0; i < 100; i++)
                lock (list)
                {
                    string _str = "Item " + list.Count + " ID=" + AppDomain.GetCurrentThreadId();
                    list.Add(_str);
                    Console.WriteLine(_str);
                }
        }
    }
}




 

Posted by gsi
:

멀티 스레드.. 정리..

C# 2007. 9. 12. 12:59 |

메세지큐에 모든 동작 상태들을 담게 된다.
그리고 그 내용을 메인 스레드에서 실제로 작업 해도 담당하게 된다.

하지만 여기서 다른 스레드와의 동기 여부가 문제가 되며,
다른 스레드에서는 메인스레드에서 생성된 인스턴스된 객체들에 바로 제어를 하지 못한다.

그래서 다른 스레드에서 하는 작업을 메세지 큐에 집어 넣고 메인 스레드가 작업은 해야 한다.
그렇기 때문에 여기서 나오는 내용들이
Invoke, BeginInvoke 가 나오게 된다.

Invoke 해당 내용이 업데이트 될때까지 기다렸다가 다음 행을 시작하게 되며,
BeginInvoke 비동기 적으로 바로 다음 행으로 진행이 되며, 나중에 업데이트가 되게 된다.

...

메인 스레드에게 이러한 작업을 실행해라 하고 다른 스레드에서 위임을 시켜 줘야 한다.

//핸들러 설정
public delegate void UpdateUIHandler(DataSet _dsTmp);

public void GetTable()
{
   Console.Write(...);
   string SQLCommentText = ...
   ....
   Thread.Sleep(1000 * 5);

   //TargetGrid가 태어난 스레드에서 실행을 하게 된다.
   TargetGrid.Invoke(new UpdateUIHandler(UpdateUI), new object[] {_dsTmp});
}

public void UpdateUI(DataSet _dsTmp)
{
   TargetGrid.DataSource = _dsTmp.Tables[0];
}

실행을 하게 되면
내가 다르게 만든 스레드에서 UpdateUI를 하게 되지만 UpdateUI는 메인 스레드에서
작업 하게 된다.

윈도우 어플리케이션에서는 스레드를 사용하지만 다른 스레드에서 사용하지 않고
메인 스레드로 위임 해서 꼭 사용해야 한다.
이럴때 사용하는게 Invoke()가 된다.

BeginInvoke를 Invoke를 사용하게 되면
다음 행은 바로 실행 되고, UpdateUI를 실행하는 스레드는 따로 진행하게 된다.

Posted by gsi
:

공도님이 소개해준 스레드 강좌.. 좋네욤.. 7편까지 있음..
http://vismuri.com/blog_category_12.aspx
Posted by gsi
: