Home  >  Article  >  Operation and Maintenance  >  There are several methods for thread synchronization

There are several methods for thread synchronization

爱喝马黛茶的安东尼
爱喝马黛茶的安东尼Original
2019-08-30 16:34:0614478browse

There are several methods for thread synchronization

What are the methods of thread synchronization? Under Linux, the system provides many ways to achieve thread synchronization, the most commonly used of which are mutex locks, condition variables and semaphores. There may be many partners who are not familiar with these three methods. The following Let me introduce it to you in detail.

Three methods to achieve thread synchronization under Linux:

1. Mutex lock (mutex)

Through lock Mechanism to achieve synchronization between threads.

1. Initialize the lock. Under Linux, the thread's mutex data type is pthread_mutex_t. Before use, it must be initialized.

Static allocation: pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

Dynamic allocation: int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr);

2. Lock. To access shared resources, the mutex must be locked. If the mutex is already locked, the calling thread will block until the mutex is unlocked.

int pthread_mutex_lock (pthread_mutex *mutex);

int pthread_mutex_trylock (pthread_mutex_t *mutex);

3. Unlock. After completing the access to the shared resource, the mutex must be unlocked.

int pthread_mutex_unlock(pthread_mutex_t *mutex);

4. Destroy the lock. After the lock is used, it needs to be destroyed to release resources.

int pthread_mutex_destroy(pthread_mutex *mutex);

#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <pthread.h>
#include "iostream"
using namespace std;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int tmp;
void* thread(void *arg)
{
cout << "thread id is " << pthread_self() << endl;
pthread_mutex_lock(&mutex);
tmp = 12;
cout << "Now a is " << tmp << endl;
pthread_mutex_unlock(&mutex);
return NULL;
}
int main()
{
pthread_t id;
cout << "main thread id is " << pthread_self() << endl;
tmp = 3;
cout << "In main func tmp = " << tmp << endl;
if (!pthread_create(&id, NULL, thread, NULL))
{
cout << "Create thread success!" << endl;
}
else
{
cout << "Create thread failed!" << endl;
}
pthread_join(id, NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
//编译:g++ -o thread testthread.cpp -lpthread

Related recommendations: "PHP Getting Started Tutorial"

2. Condition variables (cond)

Different from mutex locks, condition variables are used to wait instead of locking. Condition variables are used to automatically block a thread until a special situation occurs. Usually condition variables and mutex locks are used together. Condition variables are divided into two parts: conditions and variables. The condition itself is protected by a mutex. The thread must lock the mutex before changing the conditional state. Condition variables allow us to sleep and wait for a certain condition to occur. Condition variables are a mechanism for synchronizing using global variables shared between threads. It mainly includes two actions: one thread waits for "the condition of the condition variable to be true" and hangs; the other thread makes "the condition is true" (given that the condition is true) Signal). Detection of conditions is performed under the protection of a mutex lock. If a condition is false, a thread automatically blocks and releases the mutex waiting for the state to change. If another thread changes the condition, it signals the associated condition variable, wakes up one or more threads waiting on it, reacquires the mutex, and reevaluates the condition. If two processes share readable and writable memory, condition variables can be used to achieve thread synchronization between the two processes.

1. Initialize condition variables.

Static initialization, pthread_cond_t cond = PTHREAD_COND_INITIALIER;

Dynamic initialization, int pthread_cond_init (pthread_cond_t *cond, pthread_condattr_t *cond_attr);

2. Wait for the condition to be established. Release the lock and block waiting for the condition variable to be true. timewait() sets the waiting time, and if there is no signal, returns ETIMEOUT (locking ensures that there is only one thread wait)

int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);

int pthread_cond_timewait (pthread_cond_t *cond, pthread_mutex *mutex, const timespec *abstime);

3. Activate condition variables. pthread_cond_signal, pthread_cond_broadcast (activate all waiting threads)

int pthread_cond_signal (pthread_cond_t *cond);

int pthread_cond_broadcast (pthread_cond_t *cond); //Unblock all threads

4. Clear the condition variable. No thread is waiting, otherwise EBUSY

int pthread_cond_destroy(pthread_cond_t *cond);

[cpp] view plain copy
#include <stdio.h>
#include <pthread.h>
#include "stdlib.h"
#include "unistd.h"
pthread_mutex_t mutex;
pthread_cond_t cond;
void hander(void *arg)
{
free(arg);
(void)pthread_mutex_unlock(&mutex);
}
void *thread1(void *arg)
{
pthread_cleanup_push(hander, &mutex);
while(1)
{
printf("thread1 is running\n");
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
printf("thread1 applied the condition\n");
pthread_mutex_unlock(&mutex);
sleep(4);
}
pthread_cleanup_pop(0);
}
void *thread2(void *arg)
{
while(1)
{
printf("thread2 is running\n");
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
printf("thread2 applied the condition\n");
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main()
{
pthread_t thid1,thid2;
printf("condition variable study!\n");
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_create(&thid1, NULL, thread1, NULL);
pthread_create(&thid2, NULL, thread2, NULL);
sleep(1);
do
{
pthread_cond_signal(&cond);
}while(1);
sleep(20);
pthread_exit(0);
return 0;
}
#include <pthread.h>
#include <unistd.h>
#include "stdio.h"
#include "stdlib.h"
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
struct node
{
int n_number;
struct node *n_next;
}*head = NULL;
static void cleanup_handler(void *arg)
{
printf("Cleanup handler of second thread./n");
free(arg);
(void)pthread_mutex_unlock(&mtx);
}
static void *thread_func(void *arg)
{
struct node *p = NULL;
pthread_cleanup_push(cleanup_handler, p);
while (1)
{
//这个mutex主要是用来保证pthread_cond_wait的并发性
pthread_mutex_lock(&mtx);
while (head == NULL)
{
//这个while要特别说明一下,单个pthread_cond_wait功能很完善,为何
//这里要有一个while (head == NULL)呢?因为pthread_cond_wait里的线
//程可能会被意外唤醒,如果这个时候head != NULL,则不是我们想要的情况。
//这个时候,应该让线程继续进入pthread_cond_wait
// pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mtx,
//然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立
//而被唤醒,唤醒后,该进程会先锁定先pthread_mutex_lock(&mtx);,再读取资源
//用这个流程是比较清楚的
pthread_cond_wait(&cond, &mtx);
p = head;
head = head->n_next;
printf("Got %d from front of queue/n", p->n_number);
free(p);
}
pthread_mutex_unlock(&mtx); //临界区数据操作完毕,释放互斥锁
}
pthread_cleanup_pop(0);
return 0;
}
int main(void)
{
pthread_t tid;
int i;
struct node *p;
//子线程会一直等待资源,类似生产者和消费者,但是这里的消费者可以是多个消费者,而
//不仅仅支持普通的单个消费者,这个模型虽然简单,但是很强大
pthread_create(&tid, NULL, thread_func, NULL);
sleep(1);
for (i = 0; i < 10; i++)
{
p = (struct node*)malloc(sizeof(struct node));
p->n_number = i;
pthread_mutex_lock(&mtx); //需要操作head这个临界资源,先加锁,
p->n_next = head;
head = p;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mtx); //解锁
sleep(1);
}
printf("thread 1 wanna end the line.So cancel thread 2./n");
//关于pthread_cancel,有一点额外的说明,它是从外部终止子线程,子线程会在最近的取消点,退出
//线程,而在我们的代码里,最近的取消点肯定就是pthread_cond_wait()了。
pthread_cancel(tid);
pthread_join(tid, NULL);
printf("All done -- exiting/n");
return 0;
}

3. Semaphore (sem)

Like processes, threads can also communicate through semaphores, although they are lightweight. The names of semaphore functions all start with "sem_". There are four basic semaphore functions used by threads.

1. Semaphore initialization.

int sem_init (sem_t *sem, int pshared, unsigned int value);

This is to initialize the semaphore specified by sem and set up its sharing option (Linux only supports 0, which means it is a local semaphore of the current process), and then give it an initial value VALUE.

2. Wait for the semaphore. Decrement the semaphore by 1 and wait until the semaphore value is greater than 0.

int sem_wait(sem_t *sem);

3. Release the semaphore. Increase the semaphore value by 1. And notify other waiting threads.

int sem_post(sem_t *sem);

4. Destroy the semaphore. We clean up the semaphore after we use it. Return all resources possessed.

int sem_destroy(sem_t *sem);

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#define return_if_fail(p) if((p) == 0){printf ("[%s]:func error!/n", __func__);return;}
typedef struct _PrivInfo
{
sem_t s1;
sem_t s2;
time_t end_time;
}PrivInfo;
static void info_init (PrivInfo* thiz);
static void info_destroy (PrivInfo* thiz);
static void* pthread_func_1 (PrivInfo* thiz);
static void* pthread_func_2 (PrivInfo* thiz);
int main (int argc, char** argv)
{
pthread_t pt_1 = 0;
pthread_t pt_2 = 0;
int ret = 0;
PrivInfo* thiz = NULL;
thiz = (PrivInfo* )malloc (sizeof (PrivInfo));
if (thiz == NULL)
{
printf ("[%s]: Failed to malloc priv./n");
return -1;
}
info_init (thiz);
ret = pthread_create (&pt_1, NULL, (void*)pthread_func_1, thiz);
if (ret != 0)
{
perror ("pthread_1_create:");
}
ret = pthread_create (&pt_2, NULL, (void*)pthread_func_2, thiz);
if (ret != 0)
{
perror ("pthread_2_create:");
}
pthread_join (pt_1, NULL);
pthread_join (pt_2, NULL);
info_destroy (thiz);
return 0;
}
static void info_init (PrivInfo* thiz)
{
return_if_fail (thiz != NULL);
thiz->end_time = time(NULL) + 10;
sem_init (&thiz->s1, 0, 1);
sem_init (&thiz->s2, 0, 0);
return;
}
static void info_destroy (PrivInfo* thiz)
{
return_if_fail (thiz != NULL);
sem_destroy (&thiz->s1);
sem_destroy (&thiz->s2);
free (thiz);
thiz = NULL;
return;
}
static void* pthread_func_1 (PrivInfo* thiz)
{
return_if_fail(thiz != NULL);
while (time(NULL) < thiz->end_time)
{
sem_wait (&thiz->s2);
printf ("pthread1: pthread1 get the lock./n");
sem_post (&thiz->s1);
printf ("pthread1: pthread1 unlock/n");
sleep (1);
}
return;
}
static void* pthread_func_2 (PrivInfo* thiz)
{
return_if_fail (thiz != NULL);
while (time (NULL) < thiz->end_time)
{
sem_wait (&thiz->s1);
printf ("pthread2: pthread2 get the unlock./n");
sem_post (&thiz->s2);
printf ("pthread2: pthread2 unlock./n");
sleep (1);
}
return;
}

The above are the three commonly used methods to achieve thread synchronization under Linux. As we all know, the biggest highlight of threads It is resource sharing, and the thread synchronization problem in resource sharing is a major difficulty.

The above is the detailed content of There are several methods for thread synchronization. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn