C ++: thread synchronization script on Linux platform

I am using a multithreaded C ++ program for the Linux platform where I need functionality similar to WaitForMultipleObjects ().

When searching for a solution, I noticed that there are articles that describe how to implement WaitForMultipleObjects () functions on Linux with examples, but these examples do not satisfy the scenario that I have to support.

The scenario in my case is pretty simple. I have a daemon process in which the main thread provides a method / callback to the outside world, for example in a DLL. The dll code is not under my control. The same main thread creates a new thread "Thread 1". In thread 1, an infinite loop must be executed in which it will wait for the shutdown event (shutdown of the daemon), or it will wait until the event available to the data is transmitted through the open method / callback mentioned above.

In short, the thread will wait for the shutdown event and the available event if, in case the shutdown event is signaled that the wait will satisfy, and the cycle will be broken or if an event with data is transmitted, then the wait will satisfy, and the thread will be busy business processing.

In the windows, this seems very straightforward. Below is the pseudo-visible MS Windows code for my script.

//**Main thread** //Load the DLL LoadLibrary("some DLL") //Create a new thread hThread1 = __beginthreadex(..., &ThreadProc, ...) //callback in main thread (mentioned in above description) which would be called by the DLL void Callbackfunc(data) { qdata.push(data); SetEvent(s_hDataAvailableEvent); } void OnShutdown() { SetEvent(g_hShutdownEvent); WaitforSingleObject(hThread1,..., INFINITE); //Cleanup here } //**Thread 1** unsigned int WINAPI ThreadProc(void *pObject) { while (true) { HANDLE hEvents[2]; hEvents[0] = g_hShutdownEvent; hEvents[1] = s_hDataAvailableEvent; //3rd parameter is set to FALSE that means the wait should satisfy if state of any one of the objects is signaled. dwEvent = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE); switch (dwEvent) { case WAIT_OBJECT_0 + 0: // Shutdown event is set, break the loop return 0; case WAIT_OBJECT_0 + 1: //do business processing here break; default: // error handling } } } 

I want to implement the same for Linux. According to my understanding, when it comes to Linux, it has a completely different mechanism where we need to register for signals. If the completion signal is reached, the process finds out that it is about to stop, but before that the process must wait until the working thread is gracefully turned off.

+4
source share
2 answers

The correct way to do this on Linux would be to use condition variables. Although this is not the same as WaitForMultipleObjects on Windows, you will get the same functionality.

Use two bool to determine if data is available or whether a shutdown should occur. Then, if the shutdown function and the data function set bools accordingly and signal the condition variable.

 #include <pthread.h> pthread_cond_t cv = PTHREAD_COND_INITIALIZER; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_t hThread1; // this isn't a good name for it in linux, you'd be // better with something line "tid1" but for // comparison sake, I've kept this bool shutdown_signalled; bool data_available; void OnShutdown() { //...shutdown behavior... pthread_mutex_lock(&mutex); shutdown_signalled = true; pthread_mutex_unlock(&mutex); pthread_cond_signal(&cv); } void Callbackfunc(...) { // ... whatever needs to be done ... pthread_mutex_lock(&mutex); data_available = true; pthread_mutex_unlock(&mutex); pthread_cond_signal(&cv); } void *ThreadProc(void *args) { while(true){ pthread_mutex_lock(&mutex); while (!(shutdown_signalled || data_available)){ // wait as long as there is no data available and a shutdown // has not beeen signalled pthread_cond_wait(&cv, &mutex); } if (data_available){ //process data data_available = false; } if (shutdown_signalled){ //do the shutdown pthread_mutex_unlock(&mutex); return NULL; } pthread_mutex_unlock(&mutex); //you might be able to put the unlock // before the ifs, idk the particulars of your code } } int main(void) { shutdown_signalled = false; data_available = false; pthread_create(&hThread1, &ThreadProc, ...); pthread_join(hThread1, NULL); //... } 

I know that windows also have variable conditions, so this should not look too foreign. I don’t know what rules the windows have about them, but on the POSIX platform, wait should be inside the while , because "false awakenings" may occur.

+4
source

If you want to write unix or linux code, you have various APIs:

  • pthread: provides threads, mutex, condition variables
  • IPC mechanisms (inter process comunication): mutex, semaphore, shared memory
  • signals

For threads, the first library is required (on Linux there are lower levels of syscalls, but this is more tedious). For events, three can be used.

The system shutdown event causes the completion (SIG_TERM) and kill (SIG_KILL) of signals transmitted to all relevant processes. Therefore, the closure of a single daemon can also be triggered. The goal of the game is to catch signals and initiate a process stop. Important points:

  • the signal mechanism is designed in such a way that there is no need to wait for them

    Just install the so-called handler using sigaction , and the system will do the rest.

  • the signal is installed in the process, and any thread can intercept it (the handler can execute in any context)

    Therefore, you need to install a signal handler (see sigaction (2) ) and somehow pass information to other threads, which the application should terminate.

The most convenient way is probably a global flag protected by a mutex, which all your threads will conduct regularly. The signal handler will set this flag to indicate a shutdown. For workflow, this means

  • informs the remote host that the server is shutting down,
  • close its socket while reading
  • process all remaining received commands / data and send responses
  • close socket
  • Output

For the main thread, this will mean starting a connection in the workflow, and then exit.

This model should not interfere with the data processing method: a blocking select or poll call returns an EINTR error if the signal has been caught, and for a nonblocking call, the thread regularly checks the flag, so it works too.

+1
source

All Articles