Thread condition control realizes thread synchronization

I talked about mutex locks earlier, but I always feel that some functional mutex locks are not enough.

Condition variables are another synchronization mechanism available for threads. Condition variables provide a place for multiple threads to meet. Condition variables, when used with mutexes, allow threads to wait for a specific condition to occur in a race-free manner.

The condition itself is protected by a mutex. The thread must first lock the mutex before changing the condition state. Other threads will not notice this change until they obtain the mutex, because the mutex must be locked before the condition can be evaluated.

Conditional creation

Condition variables must be initialized before use. The condition variable represented by the pthread_cond_t data type can be initialized in two ways. The constant PTHREAD_COND_INITIALIZER can be assigned to the statically allocated condition variable, but if the condition variable is dynamically allocated, you can use the pthread_cond_destroy function to condition the condition variable. Variables are deinitialized.

Function prototype

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);

Parameters

pthread_cond_t *restrict cond: address of condition

const pthread_condattr_t *restrict attr: parameter of the condition, usually NULL is enough

Return value

Returns 0 if successful, otherwise returns an error number

Conditional destruction

Function prototype

int pthread_cond_destroy(pthread_cond_t *cond);

Parameters

pthread_cond_t *restrict cond: address of condition

Return value

Returns 0 if successful, otherwise returns an error number

Conditional trigger

These two functions can be used to notify threads that conditions have been met. The pthread_cond_signal function will wake up a thread waiting for the condition, and the pthread_cond_broadcast function will wake up all processes waiting for the condition.

Note that you must send a signal to the thread after changing the conditional state.

Function prototype

int pthread_cond_signal(pthread_cond_t *cond);

int pthread_cond_broadcast(pthread_cond_t *cond);

Return value

Returns 0 if successful, otherwise returns an error number

Conditional waiting

pthread_cond_wait waits for a condition to become true. If the condition is not met within the given time, a return variable representing an error code is generated. The mutex passed to pthread_cond_wait protects the condition, and the caller passes the locked mutex to the function. The function puts the calling thread on the list of threads waiting for the condition, and then unlocks the mutex. Both operations are atomic operations. This closes the time channel between the condition check and the thread going to sleep to wait for the condition to change, so that the thread does not miss any changes in the condition. When pthread_cond_wait returns, the mutex is locked again.

Function prototype

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, cond struct timespec *restrict timeout);

Parameters

pthread_cond_t *restrict cond: address of condition

pthread_mutex_t *restrict mutex: the address of the mutex lock

cond struct timespec *restrict timeout: timeout specifies the waiting time, which is specified through the timespec result.

Return value

Returns 0 if successful, otherwise returns an error number

Example:

When the t2 thread increases g_data to 3, the t1 thread starts running.

#include <stdio.h>
#include <pthread.h>
//int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
//int pthread_mutex_destroy(pthread_mutex_t mutex);
//int pthread_mutex_lock(pthread_mutex_t mutex);
//int pthread_mutex_trylock(pthread_mutex_t mutex);
//int pthread_mutex_unlock(pthread_mutex_t mutex)
//int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
//int pthread_cond_destroy(pthread_cond_t cond);
//int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
//int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, cond struct timespec *restrict timeout);
//int pthread_cond_signal(pthread_cond_t cond);
//int pthread_cond_broadcast(pthread_cond_t cond);

pthread_mutex_t mutex;
pthread_cond_t cond;
int g_data=0;

void *func1(void *arg)
{
        printf("t1:%ld thread is creart\
",(unsigned long)pthread_self());
        printf("t1:param is %d\
",*((int *)arg));
        pthread_mutex_lock( & amp;mutex);
        while(1)
        {
                pthread_cond_wait( & amp;cond, & amp;mutex);
                if(g_data==3)
                {
                        printf("ti run==================\
");
                }
                printf("t1:%d\
",g_data);
                g_data=0;
                sleep(1);

        }

}

void *func2(void *arg)
{
        printf("t2:%ld thread is creart\
",(unsigned long)pthread_self());
        printf("t2:param is %d\
",*((int *)arg));
        while(1)
        {
                printf("t2:%d\
",g_data);
                pthread_mutex_lock( & amp;mutex);
                g_data + + ;
                if(g_data==3)
                {
                        pthread_cond_signal( & amp;cond);
                }
                pthread_mutex_unlock( & amp;mutex);
                sleep(1);
        }
}

int main()
{
        int param=100;
        char *pret=NULL;
        int ret1;
        int ret2;
        pthread_t t1;
        pthread_t t2;

        pthread_mutex_init( & amp;mutex,NULL);
        pthread_cond_init( & amp;cond,NULL);

        ret1=pthread_create( & amp;t1, NULL,func1, (void *) & amp;param);
        ret2=pthread_create( & amp;t1, NULL,func2, (void *) & amp;param);
        if(ret1 == 0)
        {
                printf("main:create t1 successful\
");
        }

        if(ret2 == 0)
        {
                printf("main:create t2 successful\
");
        }


        pthread_join(t1,NULL);
        pthread_join(t2,NULL);

        pthread_mutex_destroy( & amp;mutex);
        pthread_cond_destroy( & amp;cond);
        return 0;
}

You can see the above code. As long as g_data is increased to 3, the t1 thread will be run, g_data will be set to 0, and then the t1 thread will exit.

The above code uses dynamic initialization of conditions and mutex locks pthread_cond_init( & amp;cond,NULL); pthread_mutex_init( & amp;mutex,NULL);, and macros can also be used for static initialization pthread_cond_t = PTHREAD_INITIALIZER; pthread_mutex_t = PTHREAD_MUTEX_INITIALIZER;

PS code testing skills

int main(int argc,char **argv)
{

        int i;
        int cnt=atoi(argv[1]);
        for(i=0;i<cnt;i + + )
        {
                system("./test");
        }
        return 0;
}

./a.out 10 >> test.ret.txt &
After the test is completed, you can view the test results in test.ret.txt. & amp; represents background running.

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. C Skill Tree Home Page Overview 194406 people are learning the system