After talking about the basics of multithreading, let's talk about some of my experiences on porting. Porting win32 program multi-thread content to Linux cannot be simply transplanted according to function correspondence. However, through the following ing, coupled with your in-depth understanding of these models, I believe it will be very successful.SemaphoresWindows semaphores are counter variables that allow limited threads/processes to access shared resources. Linux POSIX semaphores are also counter variables that can be used to implement semaphores on Windows in Linux.
- Semaphore type:Windows provides the famous named) semaphores and the unknown unnamed semaphores. A famous semaphore can be synchronized between processes. In Linux, only POSIX semaphores are used between different threads of the same process. System V semaphores can be used between processes.
- Wait for the timeout in the function:When used in a waiting function, you can specify a timeout value for the Windows semaphore object. In Linux, this function is not provided, and timeout issues can only be handled through application logic.
Create semaphoresIn Windows, you can use
CreateSemaphore()Create or open a famous or unknown semaphore.
HANDLE CreateSemaphore( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName); |
In this Code:
lpSemaphoreAttributesIs a pointer to the security attribute. If the pointer is null, the semaphore cannot be inherited.
lInitialCountIs the initial value of the semaphore.
lMaximumCountIs the maximum value of the semaphore. The value must be greater than 0.
lpNameIs the name of the semaphore. If the value is NULL, the semaphore can only be shared among different threads of the same process. Otherwise, they can be shared between different processes.
This function creates a semaphore and returns the handle of the semaphore. It also sets the initial value to the value specified in the call. This allows a limited number of threads to access a shared resource. In Linux, you can use
sem_init()Create an unknown POSIX semaphore, which can be used between threads of the same process. It also initializes the semaphore counter:
int sem_init(sem_t *sem, int pshared, unsigned int value). In this Code:
valueIs the initial value of the semaphore.
psharedIgnore this because POSIX semaphores cannot be shared among processes in the current implementation.
The maximum value is based on the SEM_VALUE_MAX defined in the demaphore. h header file. In Linux,
semget()Used to create a System V semaphore, which can be used between different integrated threads. It can be used to implement the same functions as the famous semaphores in Windows. This function returns a semaphore set identifier, which is associated with the key value of a parameter. When you create a new semaphore set
semid_dsSemaphores associated with data structures,
semget()Initialize them as follows:
sem_perm.cuidAndsem_perm.uidIt is set as the valid user ID of the calling process.
sem_perm.cgidAndsem_perm.gidIs set as the valid group ID of the calling process.
sem_perm.modeIs setsemflg9 bits.
sem_nsemsSetnsems.
sem_otimeSet to 0.
sem_ctimeIs set to the current time.
The code used to create a System V semaphore is:
int semget(key_t key, int nsems, int semflg). The following are some explanations of this Code:
keyIs a unique identifier. Different processes use it to identify this semaphore set. We can useftok()Generate a unique key value.IPC_PRIVATEIs a specialkey_tValue.IPC_PRIVATEAskeyThis system will only usesemflgBut ignore other content, so that a new semaphore set is created successfully ).
nsemsIs the number of semaphores in this semaphores set.
semflgIs the permission of the new semaphore set. To create a semaphore set, you can useIPC_CREATTo set bitwise operations or access permissions. If a semaphore set with this key already existsIPC_CREAT/IPC_EXCLThe tag will fail.
Note: In the System V semaphore,
keyUsed to uniquely identify the semaphores. In Windows, semaphores are identified by a name. To initialize the data structure of the semaphore set, you can use
IPC_SETCommand to call
semctl()System Call. Write the values of some members of the semid_ds Data Structure pointed to by arg. buf to the data structure of the semaphore set, and update the value of sem_ctime member of this structure. The user-provided arg. buf points to the semid_ds structure as follows:
sem_perm.uid
sem_perm.gid
sem_perm.modeValid at least 9 characters)
The valid user ID of the calling process should be a superuser, or at least match with the creator or owner of the semaphore set:
int semctl(int semid, int semnum, int cmd = IPC_SET, ...). In this Code:
semidIs the identifier of the semaphore set.
semnumIs the offset of the semaphore subset from 0nsems-1, where n is the number of subsets in the semaphore set ). This command is ignored.
cmdIs a command; it usesIPC_SETTo set the semaphore value.
argsIn the data structure of this semaphore setIPC_SETThe value to be updated will be explained in this example ).
The maximum counter value is defined according to
SEMVMX.
Enable semaphoresIn Windows, we use
OpenSemaphore()To open a specified semaphore. Semaphores are used only when two processes share semaphores. After the semaphore is successfully opened, the function returns the handle of the semaphore so that it can be used in subsequent calls.
HANDLE OpenSemaphore( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName) |
In this Code:
dwDesiredAccessIs the access permission requested by the semaphore object.
bInheritHandleIs a flag used to control whether the semaphore handle can inherit. If the value is TRUE, the handle can be inherited.
lpNameIs the name of the semaphore.
In Linux, you can call the same
semget()To open a semaphore. However
semflgThe value is 0:
int semget(key,nsems,0). In this Code:
keyIt should point to the key value of the semaphore set to be opened.
- To open an existing semaphore, you can
nsemsAnd the flag is set to 0.semflgThe value is set when the access permission is verified before the semaphore set identifier is returned.
Obtain semaphoresIn Windows, the wait function provides a mechanism for obtaining synchronization objects. There are multiple types of available wait functions. In this section, we only consider
WaitForSingleObject()Other types will be discussed separately ). This function uses the handle of a semaphore object as a parameter and waits until its status changes to a signal state or times out.
DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds ); In this Code:
hHandleIs a pointer to a mutex handle.
dwMillisecondsIs the timeout time, in milliseconds. If the value isINFINITEThe time it blocks the calling thread/process is uncertain.
In Linux,
sem_wait()Used to obtain access to semaphores. This function suspends the calling thread until the semaphore has a non-empty count. Then, it can reduce the value of this semaphore counter atomically:
int sem_wait(sem_t * sem). There is no timeout operation in POSIX semaphores. This can be done by executing a non-blocking
sem_trywait()This function calculates the timeout value:
int sem_trywait(sem_t * sem). When the System V semaphore is used
IPC_SETCommand
semctl()You must use
semop()To obtain the semaphore.
semop()Execute the specified operation in the operation set and block the calling thread/process until the signal value is 0 or greater:
int semop(int semid, struct sembuf *sops, unsigned nsops). Function
semop()Run
sopsOperations included in -- that is, these operations will be executed at the same time only when these operations can be successfully executed at the same time.
sopsEach
nsopsUse all elements
struct sembufSpecifies an operation to be performed on the semaphore. This structure includes the following members:
unsigned short sem_num;Number of semaphores)
short sem_op;Semaphore Operation)
short sem_flg;Operation tag)
To obtain the semaphore, you can
sem_opSet to-1 to call
semop()After using the semaphore, you can
sem_opSet to 1 to call
semop()Release semaphores. By adding
sem_opSet to-1 to call
semop(), The semaphore counter will be reduced by 1. If the value is smaller than 0, the semaphore value cannot be smaller than 0), then the semaphore cannot be reduced, but the calling thread/process will be blocked, until its status changes to a signal state.
sem_flgWhich of the following can be recognized?
IPC_NOWAITAnd
SEM_UNDO. If an operation is set
SEM_UNDOWhen the process ends, the operation is canceled. If
sem_opSet to 0, then
semop()Will wait
semvalTo 0. This is an operation that "waits for 0" and can be used to obtain the semaphore. Remember, the timeout operation is not applicable to System V semaphores. This allows you to use non-blocking
semop()By adding
sem_flgSet
IPC_NOWAIT) To calculate the timeout value.
Release semaphoresIn Windows,
ReleaseSemaphore()Used to release semaphores.
BOOL ReleaseSemaphore( HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount); |
In this Code:
hSemaphoreIs a pointer to the semaphore handle.
lReleaseCountIs a semaphore counter. You can increase the count by specifying the number.
lpPreviousCountIs the pointer to the variable returned by the previous semaphore counter. If the value of the previous semaphore counter is not requested, this parameter can be NULL.
This function will increase the semaphore counter value in
lReleaseCountAnd then set the semaphore state to a signal state. In Linux, we use
sem_post()To release semaphores. This will wake up all threads blocking the semaphore. The semaphore counter is increased by 1 at the same time. You can use a mutex variable to call the following function multiple times to add a specified value to the counter of this semaphore, just like on Windows:
int sem_post(sem_t * sem). For System V semaphores, only
semop()To release semaphores:
int semop(int semid, struct sembuf *sops, unsigned nsops). Function
semop()Atomic execution
sopsOnly when all operations can be successfully executed at the same time can all operations be completed at the same time ).
sopsEach
nsopsEach element uses
struct sembufThe structure specifies an operation to be performed on the semaphore. The structure contains the following elements:
unsigned short sem_num;Number of semaphores)
short sem_op;Semaphore Operation)
short sem_flg;Operation tag)
To release the semaphore, you can
sem_opSet to 1 to call
semop(). By adding
semop()Set to 1 to call
semop(), The counter of this semaphore will increase by 1, and the semaphore will be notified by the signal.
Disable/destroy semaphoresIn Windows, we use
CloseHandle()To close or destroy the semaphore object.
BOOL CloseHandle( HANDLE hObject); |
hObjectIs a pointer to the synchronization object handle. In Linux,
sem_destroy()Destroys the semaphore object and releases its resources:
int sem_destroy(sem_t *sem). For System V semaphores, only
semctl()Function
IPC_RMIDCommand to close the semaphore set:
int semctl(int semid, int semnum, int cmd = IPC_RMID, ...). This command will immediately delete the semaphore set and its data structure, wake up all pending processes if an error occurs, then return and
errnoSet
EIDRM). The valid user ID of the calling process must be a superuser, or a user that can match the creator or owner of the semaphore set. Parameters
semnumWill be ignored.