This example demonstrates the basic usage of Linux semaphores. In this example, two threads are used to queue and queue a public queue respectively, and the semaphore is used for control. When the queue is empty, the queuing operation can be blocked, when the queue is full, the queuing operation can be blocked.
Semaphore functions are mainly used:
Sem_init: Initialize the semaphores sem_t. during initialization, you can specify the initial semaphores and whether they can be shared among multiple processes.
Sem_wait: waits until the semaphore is greater than 0.
Sem_timedwait: blocks and waits for several times until the semaphore is greater than 0.
Sem_post: Add 1 to the semaphore.
Sem_destroy: Release the semaphore. Corresponds to sem_init.
Use man to view the specific parameters of each function. For example, man sem_init can view the help of this function.
Next let's take a look at the specificCode:
// -------------------------- Msgdequeue. h start -------------------------------------
// Implement controllable queues
# Ifndef msgdequeue_h
# Define msgdequeue_h
# Include "tmutex. H"
# Include <iostream>
# Include <errno. h>
# Include <time. h>
# Include <semaphore. h>
# Include <deque>
Using namespace STD;
template
class cmessagedequeue
{< br> Public:
cmessagedequeue (size_t maxsize): m_maxsize (maxsize)
{< br> sem_init (& m_enques, 0, m_maxsize); // The input semaphore is initialized to maxsize, up to maxsize elements can be accommodated
sem_init (& m_deques,); // The queue is empty at the beginning, the initial output semaphore is 0
}
~ Cmessagedequeue ()
{
Sem_destroy (& m_enques );
Sem_destroy (& m_deques );
}
Int sem_wait_ I (sem_t * PSEM, int mswait)
{// Wait until the semaphore is changed to> 0, and mswait is the wait time. If mswait is <0, the wait time is infinite. Otherwise, wait for several mswait milliseconds.
If (mswait <0)
{
Int Rv = 0;
While (Rv = sem_wait (PSEM ))! = 0) & (errno = eintr
); // Waiting for semaphores, errno = eintr blocks the waiting interruption caused by other signal events
Return RV;
}
Else
{
Timespec ts;
Clock_gettime (clock_realtime, & TS); // obtain the current time
TS. TV _sec + = (mswait/1000); // The number of seconds added to the wait time
TS. TV _nsec + = (mswait % 1000) * 1000; // Add the number of waiting seconds
Int Rv = 0;
While (Rv = sem_timedwait (PSEM, & TS ))! = 0) & (errno =
Eintr); // wait semaphores, errno = eintr blocks the waiting interruption caused by other signal events
Return RV;
}
}
Bool push_back (const T & item, int mswait =-1)
{// Wait for mswait in milliseconds until the item is inserted into the queue, and mswait is-1.
If (-1 = sem_wait_ I (& m_enques, mswait ))
{
Return false;
}
// Auto_guard: locks the delimiter. For details, see the tmutex. h file definition in the multi-thread and critical section programming examples in Linux.
Auto_guard (G, mutex_type, m_lock );
Try
{
M_data.push_back (item );
Cout <"push" <item <Endl;
Sem_post (& m_deques );
Return true;
}
Catch (...)
{
Return false;
}
}
Bool pop_front (T & item, bool BPOP = true, int mswait =-1)
{// Wait for mswait in milliseconds until the elements are retrieved from the queue. If mswait is-1, the system waits.
If (-1 = sem_wait_ I (& m_deques, mswait ))
{
Return false;
}
// Auto_guard: locks the delimiter. For details, see the tmutex. h file definition in the multi-thread and critical section programming examples in Linux.
Auto_guard (G, mutex_type, m_lock );
Try
{
Item = m_data.front ();
If (BPOP)
{
M_data.pop_front ();
Cout <"pop" <item <Endl;
}
Sem_post (& m_enques );
Return true;
}
Catch (...)
{
Return false;
}
}
Inline size_t size ()
{
Return m_data.size ();
}
PRIVATE:
Mutex_type m_lock;
Deque <t> m_data;
Size_t m_maxsize;
Sem_t m_enques;
Sem_t m_deques;
};
# Endif
// -------------------------- Msgdequeue. h ended -------------------------------------
// -------------------------- Test. cpp start -------------------------------------
// MasterProgramFile
# Include "msgdequeue. H"
# Include <pthread. h>
# Include <iostream>
Using namespace STD;
Cmessagedequeue <int> QQ (5 );
Void * get_thread (void * parg );
Void * put_thread (void * parg );
void * get_thread (void * parg)
{< br> while (true)
{< br> int A =-1;
If (! QQ. pop_front (A, true, 1000)
{< br> cout <"Pop failed. size = " }< BR >}< br> return NULL;
}
Void * put_thread (void * parg)
{
For (INT I = 1; I <= 30; I ++)
{
QQ. push_back (I,-1 );
}
Return NULL;
}
Int main ()
{
Pthread_t pget, pput;
Pthread_create (& pget, null, get_thread, null );
Pthread_create (& pput, null, put_thread, null );
Pthread_join (pget, null );
Pthread_join (pput, null );
Return 0;
}
// -------------------------- Test. cpp ended -------------------------------------
Compile the program: G ++ msgdequeue. h test. cpp-lpthread-LRT-o Test
-Lpthread links to the pthread library. -LTR links to the clock_gettime function library.
Compile and generate the executable file test. Enter./test execution program.
The thread get_thread retrieves elements from the queue every 1000 milliseconds, and the thread put_thread queues 30 elements in sequence. The two threads simulate the two queuing and queuing pipelines. Because the queue can contain up to five elements at cmessagedequeue <int> QQ (5, each time the number of elements in the queue reaches 5, the queue thread needs to be blocked and wait until the queue element leaves the queue. During the test, you can adjust the maximum number of elements in the queue to observe the running effect.