#include <pthread.h>
/* Define globally accessible variables and a mutex */
#define NUMTHREADS 4
pthread_t callThd[NUMTHREADS];
pthread_mutex_t lock;
void atomic_operation(void);
void *do_create(void *arg) {
/* Creation thread */
pthread_mutex_init(&lock, NULL);
pthread_exit((void*) 0);
}
void *do_work(void *arg) {
/* Worker thread */
pthread_mutex_lock (&lock);
atomic_operation();
pthread_mutex_unlock (&lock);
pthread_exit((void*) 0);
}
void *do_destroy(void *arg) {
/* Destruction thread */
pthread_mutex_destroy(&lock);
pthread_exit((void*) 0);
}
int main (int argc, char *argv[]) {
int i;
void *status;
pthread_attr_t attr;
/* Create threads */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
/* Thread that initializes mutex */
pthread_create(&callThd[0], &attr, do_create, NULL);
/* Threads that use mutex for atomic operation*/
for(i=0; i<NUMTHREADS-1; i++) {
pthread_create(&callThd[i], &attr, do_work, (void *)i);
}
/* Thread that destroys mutex */
pthread_create(&callThd[NUMTHREADS -1], &attr, do_destroy, NULL);
pthread_attr_destroy(&attr);
/* Join threads */
for(i=0; i<NUMTHREADS; i++) {
pthread_join(callThd[i], &status);
}
pthread_exit(NULL);
}В этом примере создаются четыре потока. Потокам назначаются различные действия.
Первый поток callThd[0] инициализирует мьютекс lock.
Второй и третий потоки, callThd[1] и callThd[2], выполнить атомную операцию, защищенную мьютексом lock.
Четвёртая нить callThd[3] разрушает мьютекс lock.
Потоки могут прерывать друг друга. Поэтому сразу после того, как второй или третий поток блокирует мьютекс, четвёртый поток может его уничтожить.
Исправление - инициализация и уничтожение Mutex вне процедуры запускаОдной из возможных корректировок является инициализация и уничтожение мьютекса в main вне программы запуска потоков. Потоки выполняют только атомарную операцию. Необходимо меньше двух потоков, так как потоки инициализации и уничтожения мьютекса не требуются.
#include <pthread.h>
/* Define globally accessible variables and a mutex */
#define NUMTHREADS 2
pthread_t callThd[NUMTHREADS];
pthread_mutex_t lock;
void atomic_operation(void);
void *do_work(void *arg) {
pthread_mutex_lock (&lock);
atomic_operation();
pthread_mutex_unlock (&lock);
pthread_exit((void*) 0);
}
int main (int argc, char *argv[]) {
int i;
void *status;
pthread_attr_t attr;
/* Create threads */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
/* Initialize mutex */
pthread_mutex_init(&lock, NULL);
for(i=0; i<NUMTHREADS; i++) {
pthread_create(&callThd[i], &attr, do_work, (void *)i);
}
pthread_attr_destroy(&attr);
/* Join threads */
for(i=0; i<NUMTHREADS; i++) {
pthread_join(callThd[i], &status);
}
/* Destroy mutex */
pthread_mutex_destroy(&lock);
pthread_exit(NULL);
} Исправление - используйте второй мьютекс для защиты пары блокировка-разблокировка и разрушенияДругой возможной поправкой является использование второго мьютекса и защита пары блокировка-разблокировка от разрушения. Этот исправленный код использует мьютекс lock2 для обеспечения такой защиты. Второй мьютекс инициализируется в main вне программы запуска потоков.
#include <pthread.h>
/* Define globally accessible variables and a mutex */
#define NUMTHREADS 4
pthread_t callThd[NUMTHREADS];
pthread_mutex_t lock;
pthread_mutex_t lock2;
void atomic_operation(void);
void *do_create(void *arg) {
/* Creation thread */
pthread_mutex_init(&lock, NULL);
pthread_exit((void*) 0);
}
void *do_work(void *arg) {
/* Worker thread */
pthread_mutex_lock (&lock2);
pthread_mutex_lock (&lock);
atomic_operation();
pthread_mutex_unlock (&lock);
pthread_mutex_unlock (&lock2);
pthread_exit((void*) 0);
}
void *do_destroy(void *arg) {
/* Destruction thread */
pthread_mutex_lock (&lock2);
pthread_mutex_destroy(&lock);
pthread_mutex_unlock (&lock2);
pthread_exit((void*) 0);
}
int main (int argc, char *argv[]) {
int i;
void *status;
pthread_attr_t attr;
/* Create threads */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
/* Initialize second mutex */
pthread_mutex_init(&lock2, NULL);
/* Thread that initializes first mutex */
pthread_create(&callThd[0], &attr, do_create, NULL);
/* Threads that use first mutex for atomic operation */
/* The threads use second mutex to protect first from destruction in locked state*/
for(i=0; i<NUMTHREADS-1; i++) {
pthread_create(&callThd[i], &attr, do_work, (void *)i);
}
/* Thread that destroys first mutex */
/* The thread uses the second mutex to prevent destruction of locked mutex */
pthread_create(&callThd[NUMTHREADS -1], &attr, do_destroy, NULL);
pthread_attr_destroy(&attr);
/* Join threads */
for(i=0; i<NUMTHREADS; i++) {
pthread_join(callThd[i], &status);
}
/* Destroy second mutex */
pthread_mutex_destroy(&lock2);
pthread_exit(NULL);
}