[pthread] 同步机制(1) ---- mutex & mutex attr
2009-12-30 09:15:39| 分类:
pthread
| 标签:
|举报
|字号大中小 订阅
哇,写了好几篇 pthread 的文字,终于讲到同步机制了。这个主题完成,pthread 的所有 API 就讲解完成啦。:-)
mutex 简单使用
mutex(互斥量) 的概念很简单,就是多个线程竞争一个锁。获得锁的线程 pthread_mutex_lock 会立即返回,而其他线程则会 block 在此函数上,直到此锁被 pthread_mutex_unlock 释放。
----------------------------------------
#include <stdio.h>
#include <time.h>
#include <string.h> // strerror_r
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
void *mythr(void *arg)
{
pthread_mutex_lock(&global_mutex);
printf("thr #%d getlock = %d\n", (int)arg, time(NULL));
sleep(5);
pthread_mutex_unlock(&global_mutex);
return (void *)0;
}
void *mythr2(void *arg)
{
int ret;
char buf[80];
struct timespec t;
if ( (ret = pthread_mutex_trylock(&global_mutex)) != 0 )
{
strerror_r(ret, buf, sizeof(buf));
printf("trylock fail, %d, %s\n", ret, buf);
}
else
{
printf("trylock ok\n"); // won't be here
pthread_mutex_unlock(&global_mutex);
}
clock_gettime(CLOCK_REALTIME, &t);
t.tv_sec += 2; // wait 2 sec
if ( pthread_mutex_timedlock(&global_mutex, &t) != 0 )
{
strerror_r(ret, buf, sizeof(buf));
printf("timedlock fail, %d, %s\n", ret, buf);
}
else
{
printf("timedlock ok\n"); // won't be here
pthread_mutex_unlock(&global_mutex);
}
return (void *)0;
}
int main()
{
pthread_t pid1, pid2, pid3;
pthread_create(&pid1, NULL, mythr, (void*)1);
pthread_create(&pid2, NULL, mythr, (void*)2);
sleep(1);
pthread_create(&pid3, NULL, mythr2, (void*)3);
pthread_join(pid1, NULL);
pthread_join(pid2, NULL);
pthread_join(pid3, NULL);
return 0;
}
----------------------------------------
$ ./a.out
thr #1 getlock = 1262136722
trylock fail, 16, Device busy
timedlock fail, 16, Device busy
thr #2 getlock = 1262136727
----------------------------------------
mutex 的 type
PTHREAD_MUTEX_ERRORCHECK, 一个线程两次 lock 同一个 mutex,则返回 EDEADLK。
PTHREAD_MUTEX_RECURSIVE, 允许一个线程两次 lock 同一个 mutex,不算错误。
PTHREAD_MUTEX_NORMAL, 一个线程两次 lock 同一个 mutex, 不返回错误值,直接 block 住(deadlock)。
----------------------------------------
#include <stdio.h>
#include <string.h> // strerror_r
#include <unistd.h>
#include <pthread.h>
void *mythr1(void *arg)
{
int ret;
char buf[80];
pthread_mutex_t mutex;
pthread_mutexattr_t mattr;
pthread_mutexattr_init(&mattr);
pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ERRORCHECK); // default type
pthread_mutex_init(&mutex, &mattr);
pthread_mutexattr_destroy(&mattr);
if ( (ret = pthread_mutex_lock(&mutex)) != 0 )
{
strerror_r(ret, buf, sizeof(buf));
printf("errcheck mutex, lock fail, %d, %s\n", ret, buf);
}
if ( (ret = pthread_mutex_lock(&mutex)) != 0 )
{
strerror_r(ret, buf, sizeof(buf));
printf("errcheck, lock fail, %d, %s\n", ret, buf);
}
pthread_mutex_unlock(&mutex);
return (void *)0;
}
void *mythr2(void *arg)
{
int ret;
char buf[80];
pthread_mutex_t mutex;
pthread_mutexattr_t mattr;
pthread_mutexattr_init(&mattr);
pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mutex, &mattr);
pthread_mutexattr_destroy(&mattr);
// won't be any error
if ( (ret = pthread_mutex_lock(&mutex)) != 0 )
{
strerror_r(ret, buf, sizeof(buf));
printf("errcheck mutex, lock fail, %d, %s\n", ret, buf);
}
if ( (ret = pthread_mutex_lock(&mutex)) != 0 )
{
strerror_r(ret, buf, sizeof(buf));
printf("errcheck, lock fail, %d, %s\n", ret, buf);
}
pthread_mutex_unlock(&mutex);
pthread_mutex_unlock(&mutex);
return (void *)0;
}
void *mythr3(void *arg)
{
int ret;
char buf[80];
pthread_mutex_t mutex;
pthread_mutexattr_t mattr;
pthread_mutexattr_init(&mattr);
pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_NORMAL);
pthread_mutex_init(&mutex, &mattr);
pthread_mutexattr_destroy(&mattr);
if ( (ret = pthread_mutex_lock(&mutex)) != 0 )
{
strerror_r(ret, buf, sizeof(buf));
printf("errcheck mutex, lock fail, %d, %s\n", ret, buf);
}
// deadlock here
if ( (ret = pthread_mutex_lock(&mutex)) != 0 )
{
strerror_r(ret, buf, sizeof(buf));
printf("errcheck, lock fail, %d, %s\n", ret, buf);
}
pthread_mutex_unlock(&mutex);
return (void *)0;
}
int main()
{
pthread_t pid1, pid2, pid3;
pthread_create(&pid1, NULL, mythr1, NULL);
pthread_create(&pid2, NULL, mythr2, NULL);
pthread_create(&pid3, NULL, mythr3, NULL);
pthread_join(pid1, NULL);
pthread_join(pid2, NULL);
pthread_join(pid3, NULL);
return 0;
}
----------------------------------------
$ ./a.out
errcheck, lock fail, 11, Resource deadlock avoided
----------------------------------------
mutex 的 process shared
我们可以通过 pthread_mutexattr_getpshared / setpshared 来设置此 mutex 是否允许跨进程访问。
PTHREAD_PROCESS_SHARED, 允许跨进程访问。
PTHREAD_PROCESS_PRIVATE, 不允许,此为默认值。
可惜 FreeBSD 不支持 PTHREAD_PROCESS_SHARED,无法测试其具体的使用方式,估计就是 fork() 之后,共享之。个人觉得还是 win32 的 CreateMutex 允许传入一个 const char * 来标识一个跨进程的 mutex ,用起来比较方便。
评论这张
转发至微博
转发至微博
评论