вторник, 6 ноября 2007 г.

Что такое макрос?

В двух словах макрос заменяет вызов функции ее определением через команды препроцессора:
#define Max(a,b) (((a) > (b)) ? (a) : (b))


четверг, 1 ноября 2007 г.

Семафоры.

Семафор (Semaphore) создается функцией CreateSemaphore(). Он очень похож на мьютекс, только в отличие от него у семафора есть счетчик. Семафор открыт если счетчик больше 0 и закрыт, если счетчик равен 0. Семафором обычно "огораживают" наборы равнозначных ресурсов (элементов), например очередь, список и т.п.

Пример: Классический пример использования семафора это очередь элементов, которую обрабатывают несколько потоков. Потоки "разбирают" элементы из очереди. Если очередь пуста, потоки должны "спать", ожидая появления новых элементов. Для учета элементов в очереди используется семафор.



class CMyQueue
{
HANDLE m_hSemaphore;
// Семафор для учета элементов очереди
// Описание других объектов
// для хранения элементов очереди

public:
CMyQueue()
{
m_hSemaphore = CreateSemaphore(NULL,
0,
1000, NULL);
//начальное значение счетчика = 0
//максимальное значение = 1000
// Инициализация других объектов
........
}
~CMyQueue()
{
CloseHandle( m_hSemaphore);
// Удаление других объектов
}
void AddItem(void * NewItem)
{
// Добавляем элемент в очередь
// Увеличиваем счетчик семафора на 1.
ReleaseSemaphore(m_hSemaphore,1, NULL);
}
void GetItem(void * Item)
{
// Если очередь пуста, то потоки, вызвавшие этот метод,
// будут находиться в ожидании...
WaitForSingleObject(m_hSemaphore,INFINITE);

// Удаляем элемент из очереди
}
};

Процессы & Потоки

Процессы

Процессом обычно называют экземпляр выполняемой программы.

Хотя на первый взгляд кажется, что программа и процесс понятия практически одинаковые, они фундаментально отличаются друг от друга. Программа представляет собой статический набор команд, а процесс это набор ресурсов и данных, использующихся при выполнении программы. Процесс в Windows состоит из следующих компонентов:

- Структура данных, содержащая всю информацию о процессе, в том числе список открытых дескрипторов различных системных ресурсов, уникальный идентификатор процесса, различную статистическую информацию и т.д.;

- Адресное пространство - диапазон адресов виртуальной памяти, которым может пользоваться процесс;

- Исполняемая программа и данные, проецируемые на виртуальное адресное пространство процесса.

Потоки

Процессы инертны. Отвечают же за исполнение кода, содержащегося в адресном пространстве процесса, потоки. Поток (thread) - некая сущность внутри процесса, получающая процессорное время для выполнения. В каждом процессе есть минимум один поток. Этот первичный поток создается системой автоматически при создании процесса. Далее этот поток может породить другие потоки, те в свою очередь новые и т.д. Таким образом, один процесс может владеть несколькими потоками, и тогда они одновременно исполняют код в адресном пространстве процесса. Каждый поток имеет:

- Уникальный идентификатор потока;

- Содержимое набора регистров процессора, отражающих состояние процессора;

- Два стека, один из которых используется потоком при выполнении в режиме ядра, а другой - в пользовательском режиме;

- Закрытую область памяти, называемую локальной памятью потока (thread local storage, TLS) и используемую подсистемами, run-time библиотеками и DLL.

вторник, 23 октября 2007 г.

Уважаемые коллеги!

Друзья! Убедительная просьба: пожалуйста, оставляйте комментарии к постам! Так я буду знать что мой труд не напрасен! Любые замечания и пожелания обязательно будут рассмотрены и приняты во внимание! Ели у вас появились вопросы не стесняйтесь и задавайте их в комментариях - я буду рад вам ответить, тем более что возможно эти ответы пригодятся и другим нашим коллегам! Отправить комментарий можно нажав на ссылку внизу поста, если вы стесняетесь или не хотите указывать своего имени выберете опцию "Анонимный"; если у вас нет собственной странички указывайте любую даже не существующую. Спасибо!

четверг, 11 октября 2007 г.

Мелочи на C# облегчающие жизнь: Real World Examples

Некоторые полезные мелочи которым я научился программируя на C#:

1. Вызов функции из С библиотеки:
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
extern static short QueryPerformanceCounter(ref long x);


2. Перегрузка индексатора (перегрузка оператора []):
public float this[int row, int col]
{
get
{ return GetElement(row, col); }
set
{ SetElement(row, col, value); }
}


3. Символ @ в начале строки позволяет записывать строку, не дублируя слеши, как это было в С++, то есть строка:
string FileName = "c:\\temp\\test.txt";
Полностью идентична строке:
string FileName = @"c:\temp\test.txt";
Не правда ли читабельнее! ;-)

4. Символ @ перед идентификатором (именем переменной) означает, что компилятор должен разрешить использовать данное имя идентификатора, даже если оно зарезервированоое слово:
int this = 42; // не компилируется, ошибка:
// Identifier expected, 'this' is a keyword

int @this = 42; // Компилируется нормально


5. Смело юзайте #region и #endregion для выделения секций кода. Очень помогает!

воскресенье, 16 сентября 2007 г.

Создание нетривиальных приложений на C#: Real World Examples


То, что преподают в институте зачастую весьма просто и тривиально и плохо соотносится с кодом и решениями в реальных приложениях. Поэтому, я счел, что нелишним будет знакомство читателя с реальными трудностями с которыми я столкнулся, так сказать real world examples.
Начну с самого, казалось бы, простого - с массивов. Недавно работая над научной работой наткнулся на интересную вещь: необходимо было создать в C# трехмерный массив,
причем две из трех его размерностей должны быть динамическими. И избежать этого никак было нельзя.
Как оказалось решение весьма просто - если раньше в C++ для работы с динамическими массивами использовались шаблоны библиотеки STL и работа с трехмерным указателем на массив не предвещала ровным счетом ничего хорошего, то теперь на C# объявление и использование такого массива оказывается весьма прстым и тривиальным:
Немного подумав я пришел в итоге к следующему объявлению:

 .....
/// <summary>
/// declare inner List
/// </summary>
private List<double> _arr;

/// <summary>
/// declare main List
/// </summary>
public static List<List<double>>[] Arr;
.....

Инициализация получилась также нетривиальной:

/// <summary>
/// initialize List and array
/// </summary>
private void init()
{
N = (int)numericUpDown1.Value;

Arr= new List<List<double>>[N];

for (int i = 0; i < N; i++)
{
Arr[i] = new List<List<double>>();
}
}
.....

.....
// Где-то в коде:
    _arr = new List<double>();
_arr.Add(some_value);
.....
Еще дальше:
           X[counter].Add(_x);
Y[counter].Add(_y);
t[counter].Add(_t);


Использовать массивы можно как всегда, не забывая только про правильную индексацию:


for (byte i = 0; i < Arr.Length; i++)
for (byte j = 0; j < Arr[i].Count; j++)
for (byte k = 0; k < Arr[i][j].Count - 1; k++)
.......
Arr[i][j][k];


суббота, 2 июня 2007 г.

C#, Java или С++?...

Действительно, какая разница между этими языками, ведь они все считаются С-подобными? И почему одни предпочитают Java и ненавидят C++, а другие, наоборот; и какой вообще из этих языков лучше?
Ответить на этот вопрос однозначно нельзя, но можно постараться привести доводы за и против, тогда картина станет во всяком уж случае яснее чем она была до этого.

Итак, давайте разберёмся. Начнём с С++, т.к. он из выше перечисленных языков появился раньше. В С++ реализовано практически все идиомы ООП - множественное наследование, полиморфизм, инкапсуляция, шаблоны, перегрузка операторов и т.д.. Однако возникает одно "НО". В связи с реализацией всех перечисленных выше возможностей у авторов языка появилось и множество проблем: жёсткие требования к самодисциплине программиста (в отличие, например, от Basic, Delphi, где нет различия между верхними и нижними литералами), проблемы с управлением памятью (неверное использование оператора delete), ромбовидное наследование, трудности с указателями... Язык получился весьма сложный для новичка, и весьма удобный и раскрывающий по истине необозримые просторы для деятельности профессионала. Таким образом, мы сталкиваемся с неким дуализмом: с одной стороны жесткая дисциплина, сложный язык, - с другой бесконечные просторы для программинга... С++, на мой взгляд, можно сравнить с человеческим языком, настолько развита в нем семантика выражений! Одно и тоже на С++ можно сказать тысячами способами, вот, к примеру, различные варианты того как можно вывести строку символов на экран:

cout<<"Hello!"<<endl;
cout<<"Hello!\n";
print("Test!","%s");

..... и этот список можно все продолжать и продолжать...

Со временем (что вполне естественно) появилась необходимость в усовершенствовании языка, и решения проблем, описанных выше.
Таким образом появился язык Java (в свое время я долго спорил с одним своим другом, почему язык назвали Java, рассудил нас преподаватель- это был любимый кофе программистов :)). В Java решены многие проблемы С++ - автоматическое управление памятью, нет проблем с наследованием, полная инкапсуляция. Казалось бы все замечательно, все недостатки убраны... Однако, это совсем не так! В связи с тем что до сих пор не известно как справиться с ромбовидным наследованием в Java вообще отказались от множественного наследования(!), далее: т.к. перегрузка операторов может вызывать каскадные вызовы десятков (а то и сотен) различных об'ектов и методов, то отказались и от этого!!! На Java так до сих пор и не реализована возможность создания шаблонов методов и классов(!), есть правда некое подобие этому - классы:

System.Collections.ArrayList
System.Collections.Generic.List<>

Но сравните это с мощью С++(!):

template <class T> class Matrix
{
// .....
// .....
};

Перейдём теперь к C#. Если внимательно приглядеться, то можно легко видеть, что языки C# и Java практически идентичны! Почему? Ответ очень прост: Microsoft(r)(c) скорее всего (не берусь утверждать, чтобы никого не обидеть) позаимствовала идею у программистов Sun Microsystems. Однако, компания
Microsoft(r)(c) пошла немного дальше - в C# реализована перегрузка операторов.

В заключении хотелось бы сказать пару слов о языке, который появился в MS Visual Studio 2003 - J#. Это сумасшедший гибрид C, Java и C#! Это нечто среднее между Java и C#, и, поверьте, не самое лучшее.

Подводя итоги, нужно сказать, что в последнее время появился Managed С++, в котором реализован и автоматический сборщик мусора, и т.д. и т.п.. Однако это не означает, что проблема решена и
Managed С++ является лучшим языком программирования; в конечном счёте, каждый решает сам для себя что и в какой ситуации ему использовать...