1. 程式人生 > >多執行緒與互斥物件

多執行緒與互斥物件

一、程式、程序與執行緒。

1、程式是計算機指令的集合,它以檔案的形式儲存在磁碟上。
2、程序:通常被定義為一個正在執行的程式的例項,是一個程式在其自身的地址空間中的一次執行活動。
3、程序是資源申請、排程和獨立執行的單位,因此,它使用系統中的執行資源;而程式不能申請系統資源,不能被系統排程,也不能作為獨立執行的單位,因此,它不佔用系統的執行資源。
4、程序由兩個部分組成:
a、作業系統用來管理程序的核心物件。核心物件也是系統用來存放關於程序的統計資訊的地方。
b、地址空間。它包含所有可執行模組或DLL模組的程式碼和資料。它還包含動態記憶體分配的空間。如執行緒堆疊和堆分配空間。

5、程序是不活潑的。程序從來不執行任何東西,它只是執行緒的容器。若要使程序完成某項操作,它必須擁有一個在它的環境中執行的執行緒,此執行緒負責執行包含在程序的地址空間中的程式碼。
6、單個程序可能包含若干個執行緒,這些執行緒都“同時” 執行程序地址空間中的程式碼。

7、每個程序至少擁有一個執行緒,來執行程序的地址空間中的程式碼。當建立一個程序時,作業系統會自動建立這個程序的第一個執行緒,稱為主執行緒。此後,該執行緒可以建立其他的執行緒。

8、系統賦予每個程序獨立的虛擬地址空間。對於32位程序來說,這個地址空間是4GB。

9、每個程序有它自己的私有地址空間。程序A可能有一個存放在它的地址空間中的資料結構,地址是0x12345678,而程序B則有一個完全不同的資料結構存放在它的地址空間中,地址是0x12345678。當程序A中執行的執行緒訪問地址為0x12345678的記憶體時,這些執行緒訪問的是程序A的資料結構。當程序B中執行的執行緒訪問地址為0x12345678的記憶體時,這些執行緒訪問的是程序B的資料結構。程序A中執行的執行緒不能訪問程序B的地址空間中的資料結構,反之亦然。
10、4GB是虛擬的地址空間,只是記憶體地址的一個範圍。在你能成功地訪問資料而不會出現非法訪問之前,必須賦予物理儲存器,或者將物理儲存器對映到各個部分的地址空間。
11、4GB虛擬地址空間中,2GB是核心方式分割槽,供核心程式碼、裝置驅動程式、裝置I/O高速緩衝、非頁面記憶體池的分配和程序頁面表等使用,而使用者方式分割槽使用的地址空間約為2GB,這個分割槽是程序的私有地址空間所在的地方。一個程序不能讀取、寫入、或者以任何方式訪問駐留在該分割槽中的另一個程序的資料。對於所有應用程式來說,該分割槽是維護程序的大部分資料的地方。

12、執行緒由兩個部分組成:
a、執行緒的核心物件,作業系統用它來對執行緒實施管理。核心物件也是系統用來存放執行緒統計資訊的地方。
b、執行緒堆疊,它用於維護執行緒在執行程式碼時需要的所有引數和區域性變數。
13、當建立執行緒時,系統建立一個執行緒核心物件。該執行緒核心物件不是執行緒本身,而是作業系統用來管理執行緒的較小的資料結構。可以將執行緒核心物件視為由關於執行緒的統計資訊組成的一個小型資料結構。 
14、執行緒總是在某個程序環境中建立。系統從程序的地址空間中分配記憶體,供執行緒的堆疊使用。新執行緒執行的程序環境與建立執行緒的環境相同。因此,新執行緒可以訪問程序的核心物件的所有控制代碼、程序中的所有記憶體和在這個相同的程序中的所有其他執行緒的堆疊。這使得單個程序中的多個執行緒確實能夠非常容易地互相通訊。 
15、執行緒只有一個核心物件和一個堆疊,保留的記錄很少,因此所需要的記憶體也很少。16、因為執行緒需要的開銷比程序少,因此在程式設計中經常採用多執行緒來解決程式設計問題,而儘量避免建立新的程序。

17、作業系統為每一個執行執行緒安排一定的CPU時間 —— 時間片。系統通過一種迴圈的方式為執行緒提供時間片,執行緒在自己的時間內執行,因時間片相當短,因此,給使用者的感覺,就好像執行緒是同時執行的一樣。
18、如果計算機擁有多個CPU,執行緒就能真正意義上同時運行了。

CreateThread

The CreateThread function creates a thread to execute within the virtual address space of the calling process.

To create a thread that runs in the virtual address space of another process, use theCreateRemoteThread function.

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES, // SD
  SIZE_T,                       // initial stack size
  LPTHREAD_START_ROUTINE,    // thread function
  LPVOID,                       // thread argument
  DWORD,                    // creation option
  LPDWORD                        // thread identifier
);

Parameters

lpThreadAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. IflpThreadAttributes is NULL, the handle cannot be inherited.

Windows NT/2000/XP: The lpSecurityDescriptor member of the structure specifies a security descriptor for the new thread. IflpThreadAttributes is NULL, the thread gets a default security descriptor.

指向SECURITY_ATTRIBUTES結構體的指標。這裡可以設定為NULL,使用預設的安全性。

dwStackSize
[in] Specifies the initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is zero, the new thread uses the default size for the executable. For more information, seeThread Stack Size.

指定初始提交的棧的大小,即執行緒可以將多少地址空間用於自己的棧,以位元組為單位。系統會將這個值四捨五入為最近的頁面。

如果該值是0或者小於預設提交大小,則使用和呼叫執行緒一樣的大小。

頁面是系統管理記憶體時使用的記憶體單位,不同的CPU其頁面大小也是不同的。X86 使用的頁面大小是4KB。當保留地址空間的一個區域時,系統要確保該區域的大小是系統的頁面大小的倍數。

lpStartAddress
[in] Pointer to the application-defined function of type LPTHREAD_START_ROUTINE to be executed by the thread and represents the starting address of the thread. For more information on the thread function, seeThreadProc.

指向LPTHREAD_START_ROUTINE(應用程式定義的函式型別)的指標。這個函式將被執行緒執行,表示了執行緒的起始地址,指定執行緒入口函式,該入口函式的引數型別以及返回型別要與ThreadProc()函式宣告的型別要保持一致。

lpParameter
[in] Specifies a single parameter value passed to the thread.
指定傳遞給執行緒的單獨的引數的值。
dwCreationFlags
[in] Specifies additional flags that control the creation of the thread. If the CREATE_SUSPENDED flag is specified, the thread is created in a suspended state, and will not run until theResumeThread function is called. If this value is zero, the thread runs immediately after creation. At this time, no other values are supported.

Windows XP: If the STACK_SIZE_PARAM_IS_A_RESERVATION flag is specified, thedwStackSize parameter specifies the initial reserve size of the stack. Otherwise,dwStackSize specifies the commit size.

指定控制執行緒建立的附加標記。

如果CREATE_SUSPENDED標記被指定,執行緒建立後處於暫停狀態,不會執行,直到呼叫了ResumeThread函式。    

如果該值是0,執行緒在建立之後立即執行。

lpThreadId
[out] Pointer to a variable that receives the thread identifier.

Windows NT/2000/XP: If this parameter is NULL, the thread identifier is not returned.

Windows 95/98/Me: This parameter may not be NULL.

[out]指向一個變數用來接收執行緒的識別符號。建立一個執行緒時,系統會為執行緒分配一個ID號。

Windows NT/2000:如果這個引數是NULL,執行緒的識別符號不會返回。

Windows 95/98  :這個引數不能是NULL。

如果執行緒建立成功,此函式返回執行緒的控制代碼。

Return Values

If the function succeeds, the return value is a handle to the new thread.

If the function fails, the return value is NULL. To get extended error information, callGetLastError.

Note that CreateThread may succeed even if lpStartAddress points to data, code, or is not accessible. If the start address is invalid when the thread runs, an exception occurs, and the thread terminates. Thread termination due to a invalid start address is handled as an error exit for the thread's process. This behavior is similar to the asynchronous nature ofCreateProcess, where the process is created even if it refers to invalid or missing dynamic-link libraries (DLLs).

Windows 95/98/Me: CreateThread succeeds only when it is called in the context of a 32-bit program. A 32-bit DLL cannot create an additional thread when that DLL is being called by a 16-bit program.

Remarks

The number of threads a process can create is limited by the available virtual memory. By default, every thread has one megabyte of stack space. Therefore, you can create at most 2028 threads. If you reduce the default stack size, you can create more threads. However, your application will have better performance if you create one thread per processor and build queues of requests for which the application maintains the context information. A thread would process all requests in a queue before processing requests in the next queue.

The new thread handle is created with THREAD_ALL_ACCESS to the new thread. If a security descriptor is not provided, the handle can be used in any function that requires a thread object handle. When a security descriptor is provided, an access check is performed on all subsequent uses of the handle before access is granted. If the access check denies access, the requesting process cannot use the handle to gain access to the thread. If the thread impersonates a client, then callsCreateThread with a NULL security descriptor, the thread object created has a default security descriptor which allows access only to the impersonation token's TokenDefaultDacl owner or members. For more information, seeThread Security and Access Rights.

The thread execution begins at the function specified by the lpStartAddress parameter. If this function returns, theDWORD return value is used to terminate the thread in an implicit call to theExitThread function. Use the GetExitCodeThread function to get the thread's return value.

The thread is created with a thread priority of THREAD_PRIORITY_NORMAL. Use theGetThreadPriority and SetThreadPriority functions to get and set the priority value of a thread.

When a thread terminates, the thread object attains a signaled state, satisfying any threads that were waiting on the object.

The thread object remains in the system until the thread has terminated and all handles to it have been closed through a call toCloseHandle.

The ExitProcess, ExitThread, CreateThread, CreateRemoteThread functions, and a process that is starting (as the result of a call byCreateProcess) are serialized between each other within a process. Only one of these events can happen in an address space at a time. This means that the following restrictions hold:

  • During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.
  • Only one thread in a process can be in a DLL initialization or detach routine at a time.
  • ExitProcess does not return until no threads are in their DLL initialization or detach routines.

A thread that uses functions from the C run-time libraries should use the beginthread and endthread C run-time functions for thread management rather thanCreateThread and ExitThread. Failure to do so results in small memory leaks whenExitThread is called. 

執行緒函式:

ThreadProc

The ThreadProc function is an application-defined function that serves as the starting address for a thread. Specify this address when calling theCreateThread or CreateRemoteThread function. The LPTHREAD_START_ROUTINE type defines a pointer to this callback function.ThreadProc is a placeholder for the application-defined function name.

DWORD WINAPI ThreadProc(
  LPVOID   // thread data
);

Parameters

lpParameter
[in] Receives the thread data passed to the function using the lpParameter parameter of theCreateThread or CreateRemoteThread function.

Return Values

The function should return a value that indicates its success or failure.

Remarks

A process can obtain the return value of the ThreadProc of a thread it created withCreateThread by calling the GetExitCodeThread function. A process cannot obtain the return value from theThreadProc of a thread it created with CreateRemoteThread

暫停執行緒執行:

當執行緒暫停執行的時候,也就是表示它放棄了執行的權力。
作業系統會從等待執行的執行緒佇列中選擇一個執行緒來執行。新建立的執行緒就可以得到執行的機會。
可以使用函式Sleep:

Sleep

The Sleep function suspends the execution of the current thread for the specified interval.

To enter an alertable wait state, use the SleepEx function.

VOID Sleep(
  DWORD   // sleep time,以毫秒為單位
);

Parameters

dwMilliseconds
[in] Specifies the time, in milliseconds, for which to suspend execution. A value of zero causes the thread to relinquish the remainder of its time slice to any other thread of equal priority that is ready to run. If there are no other threads of equal priority ready to run, the function returns immediately, and the thread continues execution. A value of INFINITE causes an infinite delay.

Return Values

This function does not return a value.

Remarks

A thread can relinquish the remainder of its time slice by calling this function with a sleep time of zero milliseconds.

You have to be careful when using Sleep and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. If you have a thread that uses Sleep with infinite delay, the system will deadlock. Two examples of code that indirectly creates windows are DDE and COMCoInitialize. Therefore, if you have a thread that creates windows, useMsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than Sleep.

eg:

HANDLE hThread;
hThread=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
CloseHandle(hThread);
Sleep(10);
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
    ;
}

</pre><p></p><pre>
二、互斥物件。

1、互斥物件(mutex)屬於核心物件,它能夠確保執行緒擁有對單個資源的互斥訪問權。2、互斥物件包含一個使用數量,一個執行緒ID和一個計數器。3、ID用於標識系統中的哪個執行緒當前擁有互斥物件,計數器用於指明該執行緒擁有互斥物件的次數。

CreateMutex

The CreateMutex function creates or opens a named or unnamed mutex object.

HANDLE CreateMutex(
  LPSECURITY_ATTRIBUTES,  // SD
  BOOL,                       // initial owner
  LPCTSTR                            // object name
);

Parameters

lpMutexAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. IflpMutexAttributes is NULL, the handle cannot be inherited.
指向SECURITY_ATTRIBUTES結構體的指標。可以傳遞NULL,讓其使用預設的安全性。
 

Windows NT/2000/XP: The lpSecurityDescriptor member of the structure specifies a security descriptor for the new mutex. IflpMutexAttributes is NULL, the mutex gets a default security descriptor.

bInitialOwner
[in] Specifies the initial owner of the mutex object. If this value is TRUE and the caller created the mutex, the calling thread obtains ownership of the mutex object. Otherwise, the calling thread does not obtain ownership of the mutex. To determine if the caller created the mutex, see the Return Values section.
指示互斥物件的初始擁有者。 如果該值是真,呼叫者建立互斥物件,呼叫的執行緒獲得互斥物件的所有權。 否則,呼叫執行緒捕獲的互斥物件的所有權。(就是說,如果該引數為真,則呼叫該函式的執行緒擁有互斥物件的所有權。否則,不擁有所有權,當前互斥物件處於空閒狀態,其他執行緒可以佔用)
lpName
[in] Pointer to a null-terminated string specifying the name of the mutex object. The name is limited to MAX_PATH characters. Name comparison is case sensitive.
互斥物件名稱。傳遞NULL建立的就是沒有名字的互斥物件,即匿名的互斥物件。
 

If lpName matches the name of an existing named mutex object, this function requests MUTEX_ALL_ACCESS access to the existing object. In this case, thebInitialOwner parameter is ignored because it has already been set by the creating process. If thelpMutexAttributes parameter is not NULL, it determines whether the handle can be inherited, but its security-descriptor member is ignored.

If lpName is NULL, the mutex object is created without a name.

If lpName matches the name of an existing event, semaphore, waitable timer, job, or file-mapping object, the function fails and theGetLastError function returns ERROR_INVALID_HANDLE. This occurs because these objects share the same name space.

Terminal Services: The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Name Spaces.

Windows XP: Fast user switching is implemented using Terminal Services sessions. The first user to log on uses session 0, the next user to log on uses session 1, and so on. Kernel object names must follow the guidelines outlined for Terminal Services so that applications can support multiple users.

Windows 2000: If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.

Windows NT 4.0 and earlier: The name can contain any character except the backslash character.

Windows 95/98/Me: The name can contain any character except the backslash character. The empty string ("") is a valid object name.

Return Values

If the function succeeds, the return value is a handle to the mutex object. If the named mutex object existed before the function call, the function returns a handle to the existing object andGetLastError returns ERROR_ALREADY_EXISTS. Otherwise, the caller created the mutex.

If the function fails, the return value is NULL. To get extended error information, callGetLastError.

建立成功之後 ,返回一個互斥物件控制代碼。如果一個命名的互斥物件在本函式呼叫之前已經存在,則返回已經存在的物件控制代碼。然後可以呼叫GetLastError檢查其返回值是否為ERROR_ALREADY_EXISTS,TRUE則表示命名互斥物件已經存在,否則表示互斥物件是新建立的。

Remarks

The handle returned by CreateMutex has MUTEX_ALL_ACCESS access to the new mutex object and can be used in any function that requires a handle to a mutex object.

Any thread of the calling process can specify the mutex-object handle in a call to one of thewait functions. The single-object wait functions return when the state of the specified object is signaled. The multiple-object wait functions can be instructed to return either when any one or when all of the specified objects are signaled. When a wait function returns, the waiting thread is released to continue its execution.

The state of a mutex object is signaled when it is not owned by any thread. The creating thread can use thebInitialOwner flag to request immediate ownership of the mutex. Otherwise, a thread must use one of the wait functions to request ownership. When the mutex's state is signaled, one waiting thread is granted ownership, the mutex's state changes to nonsignaled, and the wait function returns. Only one thread can own a mutex at any given time. The owning thread uses theReleaseMutex function to release its ownership.

The thread that owns a mutex can specify the same mutex in repeated wait function calls without blocking its execution. Typically, you would not wait repeatedly for the same mutex, but this mechanism prevents a thread from deadlocking itself while waiting for a mutex that it already owns. However, to release its ownership, the thread must callReleaseMutex once for each time that the mutex satisfied a wait.

Two or more processes can call CreateMutex to create the same named mutex. The first process actually creates the mutex, and subsequent processes open a handle to the existing mutex. This enables multiple processes to get handles of the same mutex, while relieving the user of the responsibility of ensuring that the creating process is started first. When using this technique, you should set thebInitialOwner flag to FALSE; otherwise, it can be difficult to be certain which process has initial ownership.

Multiple processes can have handles of the same mutex object, enabling use of the object for interprocess synchronization. The following object-sharing mechanisms are available:

  • A child process created by the CreateProcess function can inherit a handle to a mutex object if thelpMutexAttributes parameter of CreateMutex enabled inheritance.
  • A process can specify the mutex-object handle in a call to the DuplicateHandle function to create a duplicate handle that can be used by another process.
  • A process can specify the name of a mutex object in a call to the OpenMutex orCreateMutex function.

Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The mutex object is destroyed when its last handle has been closed.

Windows 95/98/Me: CreateMutexW is supported by the Microsoft Layer for Unicode. To use this, you must add certain files to your application, as outlined inMicrosoft Layer for Unicode on Windows 95/98/Me Systems.

WaitForSingleObject

等待互斥物件的使用權,如果第二個引數設定為INFINITE,則表示會持續等待下去,直到擁有所有權,才有權執行該函式下面的語句。一旦擁有了所有權,則會將互斥物件的的執行緒ID設定為當前使用的執行緒ID值。

The WaitForSingleObject function returns when one of the following occurs:

  • The specified object is in the signaled state.
  • The time-out interval elapses.

To enter an alertable wait state, use the WaitForSingleObjectEx function. To wait for multiple objects, use theWaitForMultipleObjects.

DWORD WaitForSingleObject(
  HANDLE,        // handle to object
  DWORD   // time-out interval
);

Parameters

hHandle
[in] Handle to the object. For a list of the object types whose handles can be specified, see the following Remarks section.

If this handle is closed while the wait is still pending, the function's behavior is undefined.

Windows NT/2000/XP: The handle must have SYNCHRONIZE access. For more information, seeStandard Access Rights.

dwMilliseconds
[in] Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the object's state is nonsignaled. IfdwMilliseconds is zero, the function tests the object's state and returns immediately. IfdwMilliseconds is INFINITE, the function's time-out interval never elapses.

Return Values

If the function succeeds, the return value indicates the event that caused the function to return. This value can be one of the following.

Value Meaning
WAIT_ABANDONED The specified object is a mutex object that was not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.
WAIT_OBJECT_0 The state of the specified object is signaled.
WAIT_TIMEOUT The time-out interval elapsed, and the object's state is nonsignaled.

If the function fails, the return value is WAIT_FAILED. To get extended error information, callGetLastError.

Remarks

The WaitForSingleObject function checks the current state of the specified object. If the object's state is nonsignaled, the calling thread enters the wait state. It uses no processor time while waiting for the object state to become signaled or the time-out interval to elapse.

The function modifies the state of some types of synchronization objects. Modification occurs only for the object whose signaled state caused the function to return. For example, the count of a semaphore object is decreased by one.

The WaitForSingleObject function can wait for the following objects:

  • Change notification
  • Console input
  • Event
  • Job
  • Mutex
  • Process
  • Semaphore
  • Thread
  • Waitable timer

Use caution when calling the wait functions and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. A thread that uses a wait function with no time-out interval may cause the system to become deadlocked. Two examples of code that indirectly creates windows are DDE and COMCoInitialize. Therefore, if you have a thread that creates windows, useMsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than WaitForSingleObject.


ReleaseMutex

The ReleaseMutex function releases ownership of the specified mutex object.

BOOL ReleaseMutex(
  HANDLE   // handle to mutex
);

Parameters

hMutex
[in] Handle to the mutex object. The CreateMutex orOpenMutex function returns this handle.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, callGetLastError.

Remarks

The ReleaseMutex function fails if the calling thread does not own the mutex object.

A thread gets ownership of a mutex by specifying a handle to the mutex in one of thewait functions. The thread that creates a mutex object can also get immediate ownership without using one of the wait functions. When the owning thread no longer needs to own the mutex object, it calls theReleaseMutex function.

While a thread has ownership of a mutex, it can specify the same mutex in additional wait-function calls without blocking its execution. This prevents a thread from deadlocking itself while waiting for a mutex that it already owns. However, to release its ownership, the thread must call ReleaseMutex once for each time that the mutex satisfied a wait. 

可以將互斥物件想象成一把鑰匙,CreateMutex建立了這把鑰匙,WaitForSingleObject等待這把鑰匙去訪問一個公共的資源,比如一個房間,如果擁有了鑰匙,則這個房間的所有權就屬於這個程序了,別人是進不去這個房間的,直到程序將這個房間的鑰匙歸還掉,即ReleaseMutex。

eg:

#include <windows.h>
#include <iostream.h>

DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
);

DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
);
int index=0;
int tickets=100;
HANDLE hMutex;
void main()
{
	HANDLE hThread1;
	HANDLE hThread2;
	hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
	hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
	CloseHandle(hThread1);
	CloseHandle(hThread2);
	/*while(index++<1000)
		cout<<"main thread is running"<<endl;*/
	//hMutex=CreateMutex(NULL,TRUE,NULL);
	hMutex=CreateMutex(NULL,TRUE,"tickets");//因為TRUE,該執行緒(主執行緒)獲得互斥物件的所有權,計數器+1。
	if(hMutex)
	{
		if(ERROR_ALREADY_EXISTS==GetLastError())
		{
			cout<<"only instance can run!"<<endl;
			return;
		}
	}
	WaitForSingleObject(hMutex,INFINITE);//等待到互斥物件所有權後,計數器再+1,此時計時器=2.
	ReleaseMutex(hMutex);//釋放互斥物件所有權,此時計時器2-1=1.
	ReleaseMutex(hMutex);//此時計時器1-1=0.
	Sleep(4000);//暫停執行緒的執行,放棄互斥物件所有權。
//	Sleep(10);
}

DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
)
{
	/*while(index++<1000)
		cout<<"thread1 is running"<<endl;*/
	
	while(TRUE)
	{
		//ReleaseMutex(hMutex);
		WaitForSingleObject(hMutex,INFINITE);
		if(tickets>0)
		{
			Sleep(1);
			cout<<"thread1 sell ticket : "<<tickets--<<endl;
		}
		else
			break;
		ReleaseMutex(hMutex);
	}

	WaitForSingleObject(hMutex,INFINITE);
	cout<<"thread1 is running"<<endl;
	return 0;
}

DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
)
{
	
	while(TRUE)
	{
		//ReleaseMutex(hMutex);
		WaitForSingleObject(hMutex,INFINITE);
		if(tickets>0)
		{
			Sleep(1);
			cout<<"thread2 sell ticket : "<<tickets--<<endl;
		}
		else
			break;
		ReleaseMutex(hMutex);
	}
	WaitForSingleObject(hMutex,INFINITE);
	cout<<"thread2 is running"<<endl;
	return 0;
}


孫鑫老師深入詳解VC++筆記。

相關推薦

執行互斥物件

一、程式、程序與執行緒。 1、程式是計算機指令的集合,它以檔案的形式儲存在磁碟上。 2、程序:通常被定義為一個正在執行的程式的例項,是一個程式在其自身的地址空間中的一次執行活動。 3、程序是資源申請、排程和獨立執行的單位,因此,它使用系統中的執行資源;而程式不能申請系統資源

執行同步-互斥物件(深入理解Mutex)

多執行緒之執行緒同步Mutex (功能與Critial Sections相同,但是屬於核心物件,訪問速度較慢,可以被不同程序呼叫)一 Mutex 互斥物件(mutex)核心物件能夠確保執行緒擁有對單個資源的互斥訪問權。實際上互斥物件是因此而得名的。互斥物件包含一個使用數量,

Visual C++網路程式設計經典案例詳解 第3章 執行非同步套接字程式設計 實現執行同步 互斥物件 使用API函式操作互斥物件

互斥物件和臨界區物件和事件物件作用一樣 用於實現執行緒同步 互斥物件可以線上程中使用 CreateMutex()建立並返回互斥物件 原型如下 HANDLE CreateMutex(   LPSECURITY_ATTIRIBUTES lpMutexAttributes,  

Visual C++網路程式設計經典案例詳解 第3章 執行非同步套接字程式設計 實現執行同步 互斥物件 程式的唯一執行

互斥物件可在程序中使用 使用者在程序建立互斥物件實現程式例項唯一執行 建立控制檯工程 #include<windows.h>                                //包含標頭檔案 #include<stdio.h> in

QT執行中,物件訊號槽連線不上的解決辦法

1、在接收者建立執行緒中,把接收者移動到主執行緒中: pReceiverObj->moveToThread(QApplication::instance()->thread()); 2、這樣傳送訊號的時候,就會在主執行緒事件佇列處理中來處理了。 把connect的最

執行,執行同步互斥

程序:只是分配資源的單位 , 不執行指令(是而靠執行緒執行指令)執行緒 (#include<pthread.h>)  (Thread輕量級的程序):程序內部的一條執行路徑(俗稱程序的輕量級) 主執行緒:每一個程序必須有一個預設執行緒,稱為主執行緒(執行主函式) 執

Thread三種實現&執行操作同一物件互斥同步以及物件的同步&定時器Timer

多執行緒 程序 程序:(Process)是計算機中的程式關於某資料集合上的一次執行活動,是系統進行資源分配和排程的基本單位,是作業系統結構的基礎。在程序是程式的基本執行實體,在當代面向執行緒設計的計算機結構中,程序是執行緒的容器,程是程式的實體。 多執行緒:是指從

執行單例物件之間的關係

在我在考慮考慮他們的時候思考了以下幾個問題: 1、我們通常都將dao層(資料庫連線層)設定成單例,這樣的話如果每次處理資料庫中的資料都需要同一個物件去處理的話,處理資料的效能完全得不到保證。 2、ssh中為什麼struts2中的action層必須建立多例?而

【Java執行併發庫】3.傳統執行互斥技術

執行緒的同步互斥與通訊 互斥的問題在使用執行緒的時候是我們必須要注意的。 例如兩個執行緒同時開啟,由於業務規則,需要訪問同一個物件,要取得該物件 中的資料進行修改。 這樣多個執行緒對同一個資料進行操作的例項有很多,例如銀行交易。我們的賬戶中原來 有2000元,在同一時間,我

Java執行基礎之物件鎖的同步非同步

同步:synchronized 同步的概念就是共享,如果不是共享的資源,就沒有必要進行同步。 非同步:asynchronized 非同步的概念就是獨立,相互之間不受到任何制約。 同步的目的就是為了執行緒安全,對於

Java執行中的物件互斥

1、為什麼會有鎖? 在看執行緒同步的問題之前,我們先看一個生活中的小例子: 我拿著銀行卡去ATM取錢,假如我的卡里有3000塊,我要取走2000,這個時候,ATM會去銀行的資料庫裡查詢我的賬戶是否有2000以上的餘額,如果有,就會讓我取走,不幸的是,這個時候

執行互斥鎖(By C++)程序

#include<Windows.h> #include<iostream> using namespace std; //互斥鎖 HANDLE hMutex1; HANDLE hMutex2; int flag; DWORD WINAPI MyThread2(LPVOID lp

Java執行併發應用-(6)-執行之間共享物件和資料的方式

此內容來自張孝祥老師的java多執行緒與併發庫高階應用 如果多個執行緒執行的程式碼相同,可以使用同一個Runnable物件,這個Runnable物件中有那個共享資料。 如果多個執行緒執行的程式碼不同,這時候需要用不同的Runnable物件。將共享物件封裝在另一個物件中,然後

執行高併發基礎知識

一、概覽 多執行緒主要知識點: 執行緒安全、執行緒封閉、執行緒排程、同步容器、併發容器、AQS、J.U.C 高併發解決方案: 擴容、快取、佇列、拆分、服務降級與熔斷、資料庫切庫、分庫分表 二、併發 概念: 同時擁有兩個或者多個執行緒,如果程式在單核處理器上執行

執行基礎7 執行併發庫

多執行緒與併發庫 BlockingQueue佇列 BlockingQueue,如果BlockQueue是空的,從BlockingQueue取東西的操作將會被阻斷進入等待狀態,直到BlockingQueue進了東西才會被喚醒.同樣,如果BlockingQueue是滿的,任何試圖往裡存東西的操作

2017.10.12 C#執行非同步的區別

最近在寫個多執行緒處理的程式,又重新溫習了一下相關知識,記錄在這裡。 C#多執行緒與非同步的區別 原文地址:http://kb.cnblogs.com/page/116095/ 多執行緒和非同步操作的異同   多執行緒和非同步操作兩者都可以達到避免呼叫執行緒阻塞的目的,從而提高軟體

Qt 筆記:執行介面元件的通訊(上)

是否可以在子執行緒中建立介面元件? class TestThread : public QThread { Q_OBJECT protected: void run() { QWidget w; w.show();

Qt:筆記:執行介面元件的通訊(下)

子執行緒能夠更改介面元件狀態的本質是什麼? -子執行緒發射訊號通知主執行緒介面更新請求;主執行緒根據具體訊號遺蹟訊號引數對介面元件進行修改。 是否有其他間接的方式可以讓子執行緒更新介面元件的狀態? 解決方案 - 傳送自定義事件 -自定義事件類用於描述介面更新細節 -在主視窗類中重

python執行————8、執行程序對比

#多程序程式設計 #耗cpu的操作,用多程序程式設計,對於io操作來說,使用多執行緒程式設計,程序切換代價要高於執行緒 import time from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor,as_compl

執行加鎖的一些理解

競爭發生在當多執行緒同時訪問同一個記憶體,各個執行緒執行的順序有交叉時。 一般來說,區域性變數和引數由於對每個執行緒是獨立的,不會發生競爭。競爭通常發生在全域性變數,堆變數等上。 解決競爭最簡單的方法就是進入臨界區(開始讀寫公共記憶體)時遮蔽掉中斷,但是這種方法對於多