);
Замечание: для «чистоты эксперимента» возможно, стоит создавать потоки в «приостановленном» (suspended) состоянии, а затем (когда все сформированы) возобновить их выполнение (ResumeThread)
Поэкспериментируйте с приоритетами потоков.
В GUI-приложении проще и нагляднее для изменения приоритетов потоков ввести для каждого потока переключатели (достаточно трех radio buttons для каждого потока: нормальный, чуть повыше нормального, чуть повыше)
Функция для установки приоритета - SetThreadPriority()
Основные понятия:
1) сформировать структуру данных типа CRITICAL_SECTION (она может быть глобальной, локальной или динамической – главное, чтобы она существовала, пока ею кто-нибудь пользуется).
CRITICAL_SECTION cs; //поля этой структуры недокументированны. Пользоваться ею можно только посредством соответствующих Win32 API
2) прежде чем синхронизировать потоки с помощью критической секции, нужно ее инициализировать вызовом функции:
InitializeCriticalSection(&cs);
3) перед каждым (в обоих потоках) блоком, который модифицирует данные, вызвать
EnterCriticalSection(&cs);//блокирует данный поток, если эта критическая секция уже «занята» другим потоком. Это означает, что поток не может выполнить код, который «защищен» критической секцией => отправляется ОС в спячку.
Функция, анализируя поля структуры cs (некоторый счетчик ссылок), выясняет – вызвана ли она в первый раз (если счетчик нулевой). В этом случае функция увеличивает счетчик и разрешает выполнение потока дальше (то есть выполняется блок, модифицирующий данные). Допустим, в это время истекает квант времени, отпущенный данному потоку, или он вытесняется более приоритетным потоком, использующим те же данные: поток выполняется, пока не встречает функцию EnterCriticalSection(), функция выясняет, что объект cs уже «занят», она приостанавливает данный поток (он «засыпает»), а остаток процессорного времени система передает другому потоку.
4) после выполнения этого блока вызвать
LeaveCriticalSection(&cs);
Эта функция уменьшает счетчик ссылок. Как только поток “освобождает” критическую секцию (счетчик ссылок становится 0), система “будит” ожидающий поток, снимая защиту от модификации данных.
5) когда надобность в синхронизации потоков отпадает, следует вызвать
DeleteCriticalSection(&cs);
Эта функция освобождает все ресурсы, включенные в критическую секцию.
Основные понятия:
HANDLE CreateMutex(//если мьютекс создать не удалось - 0
LPSECURITY_ATTRIBUTES lpMutexAttributes,
BOOL bInitialOwner, //TRUE - позволяет вызывающему функцию потоку немедленно вступить во владение мьютексом при его создании (этот флаг игнорируется, если мьютекс уже существует) если TRUE, поток, создающий мьютекс, изначально имеет доступ к ресурсу, контролируемому мьютексом => мьютекс оказывается в занятом состоянии=> любой другой поток, ожидающий данный мьютекс, будет приостановлен, пока поток, создавший этот объект, не освободит его. Если параметр равен FALSE, это означает, что мьютекс не принадлежит ни одному из потоков => первый же поток из числа ожидающих этот объект может занять его и тем самым продолжить свое выполнение.
LPCTSTR lpName ); //имя объекта ядра или 0
Замечание: если Вы знаете, что существует мьютекс с данным именем, и Вы хотите сделать этот объект доступным другим процессам, нет нужды обращаться к CreateMutex(). Есть способ, получить описатель уже существующего мьютекса:
HANDLE OpenMutex( DWORD dwDesiredAccess, //стандартные (DELETE, READ_CONTROL, SYNCHRONIZE, WRITE_DAC, and WRITE_OWNER) + специфические для мьютекса - MUTEX_ALL_ACCESS и MUTEX_MODIFY_STATE
BOOL bInheritHandle, //если TRUE, дочерний процесс //наследует возвращаемый описатель мьютекса
LPCTSTR lpName ); //указатель на строку и именем мьютекса
При вызове OpenMutex() система сканирует существующие объекты-мьютексы, проверяя – нет ли среди них объекта с именем, указанным в lpName. Обнаружив таковой, она создает описатель объекта, специфичный для данного процесса, и возвращает его вызвавшему потоку. В дальнейшем любой поток из данного процесса может использовать этот описатель при вызове любой функции, требующей такой описатель. А если объекта с таким именем нет, функция возвращает 0.
Когда требуется освободить объект –
BOOL ReleaseMutex(HANDLE hObject);//Замечание: если поток не владеет данным мьютексом - FALSE
Когда мьютекс Вам больше не нужен, вызовите функцию
BOOL CloseHandle(HANDLE hObject); //где hObject – описатель мьютекса, возвращенный функцией CreateMutex()
Посредством именованного мьютекса синхронизируйте выполнение потоков в разных процессах.
Основные понятия:
Объект-семафор создается функцией:
HANDLE CreateSemaphore(//если семафор создать не удалось, возвращаемое значение 0
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.