스레드 동기화 방법은 무엇입니까? Linux에서 시스템은 스레드 동기화를 달성하기 위한 다양한 방법을 제공하며, 그 중 가장 일반적으로 사용되는 방법은 뮤텍스 잠금, 조건 변수 및 세마포어입니다. 이 세 가지 방법에 익숙하지 않은 파트너가 많을 수 있습니다. 다음에서 소개하겠습니다. 상세히.
Linux에서 스레드 동기화를 달성하는 세 가지 방법:
1. 뮤텍스(mutex)
스레드 간의 동기화는 잠금 메커니즘을 통해 달성됩니다.
1. 잠금을 초기화합니다. Linux에서 스레드의 뮤텍스 데이터 유형은 pthread_mutex_t입니다. 사용하기 전에 초기화를 해야 합니다.
정적 할당: pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
동적 할당: int pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr); 공유 리소스에 액세스하려면 뮤텍스를 잠가야 합니다. 뮤텍스가 이미 잠겨 있으면 호출 스레드는 뮤텍스가 잠금 해제될 때까지 차단됩니다.
int pthread_mutex_lock(pthread_mutex *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex); 공유 리소스에 대한 액세스를 완료한 후에는 뮤텍스를 잠금 해제해야 합니다.
int pthread_mutex_unlock (pthread_mutex_t *mutex)
4. 잠금을 사용한 후에는 리소스를 해제하기 위해 잠금을 파기해야 합니다.
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
관련 권장 사항: "
PHP 시작하기 튜토리얼
뮤텍스 잠금과 달리 조건 변수를 사용하여 대기 잠금용이 아닙니다. 조건 변수는 특별한 상황이 발생할 때까지 스레드를 자동으로 차단하는 데 사용됩니다. 일반적으로 조건 변수와 뮤텍스 잠금은 함께 사용됩니다. 조건 변수는 조건과 변수라는 두 부분으로 나뉩니다. 조건 자체는 뮤텍스로 보호됩니다. 스레드는 조건부 상태를 변경하기 전에 뮤텍스를 잠가야 합니다. 조건 변수를 사용하면 잠을 자고 특정 조건이 발생할 때까지 기다릴 수 있습니다. 조건 변수는 스레드 간에 공유되는 전역 변수를 사용하여 동기화하는 메커니즘입니다. 여기에는 주로 두 가지 작업이 포함됩니다. 하나의 스레드는 "조건 변수의 조건이 true"가 될 때까지 기다리고 다른 스레드는 "조건이 true"가 되도록 합니다. 조건이 참인지 확인) 신호). 조건 감지는 뮤텍스 잠금 보호 하에 수행됩니다. 조건이 false이면 스레드는 상태가 변경되기를 기다리는 뮤텍스를 자동으로 차단하고 해제합니다. 다른 스레드가 조건을 변경하면 관련 조건 변수에 신호를 보내고 이를 기다리고 있는 하나 이상의 스레드를 깨운 다음 뮤텍스를 다시 획득하고 조건을 다시 평가합니다. 두 프로세스가 읽기 및 쓰기 가능한 메모리를 공유하는 경우 조건 변수를 사용하여 두 프로세스 간의 스레드 동기화를 달성할 수 있습니다.
1. 조건변수를 초기화합니다.
정적 초기화, pthread_cond_t cond = PTHREAD_COND_INITIALIER;
동적 초기화, int pthread_cond_init (pthread_cond_t *cond, pthread_condattr_t *cond_attr)
2. 조건이 성립됩니다. 잠금을 해제하고 조건 변수가 true가 될 때까지 대기합니다. timewait()는 대기 시간을 설정하지만 여전히 신호가 없으며 ETIMEOUT을 반환합니다(잠금을 사용하면 스레드 대기가 하나만 있음을 보장함)
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. pthread_cond_signal, pthread_cond_broidcast (모든 대기 스레드 활성화)
INT PTHREAD_COND_SIGNAL (pthread_cond_t *cond) *cond); // 모든 스레드의 블록 4를 놓고 조건 변수를 지웁니다. 대기 중인 스레드가 없으면 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. 프로세스와 마찬가지로 스레드도 세마포어를 통해 통신할 수 있지만 규모는 작습니다. 세마포어 함수의 이름은 모두 "sem_"으로 시작합니다. 스레드에서 사용하는 네 가지 기본 세마포어 함수가 있습니다.
1. 세마포어 초기화.
int sem_init (sem_t *sem, int pshared, unsigned int value)
이것은 sem이 지정한 세마포어를 초기화하고 공유 옵션을 설정하는 것입니다. (리눅스는 0만 지원합니다. 즉, 현재의 로컬 세마포어입니다. 프로세스) 그런 다음 초기값 VALUE를 제공합니다.
2. 세마포어를 기다립니다. 세마포어를 1만큼 감소시키고 세마포어 값이 0보다 커질 때까지 기다립니다.
int sem_wait (sem_t *sem)
3. 세마포어 값을 1만큼 늘립니다. 그리고 다른 대기 스레드에 알립니다.
int sem_post (sem_t *sem)
4. 우리는 세마포어를 사용한 후에 이를 정리합니다. 보유하고 있는 모든 자원을 반환합니다.
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; }
위는 Linux에서 스레드 동기화를 달성하기 위해 일반적으로 사용되는 세 가지 방법입니다. 우리 모두 알고 있듯이 스레드의 가장 큰 특징은 리소스 공유입니다. 동기화 문제는 큰 어려움입니다.
위 내용은 스레드 동기화에는 여러 가지 방법이 있습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!