使用互斥锁pthread_mutex_t
有两种方法可以创建互斥:静态方法和动态方法。 在POSIX中,通过定义宏PTHREAD_MUTEX_INITIALIZER静态初始化互斥锁,如下所示:
pthread _ mutex _ t mutex=pthread _ mutex _ initializer;
在LinuxThreads实现中,pthread_mutex_t是一个结构,而PTHREAD_MUTEX_INITIALIZER是结构常量。
动态使用pthread_mutex_init ()函数初始化互斥锁。 API的定义如下:
int pthread _ mutex _ init (pthread _ mutex _ t * mutex,const pthread _ mutexattr _ t * mutexattr ) )。
其中mutexattr指定互斥锁属性,如果为NULL,则使用默认属性。
pthread_mutex_destroy ()用于释放互斥锁,API的定义如下:
int pthread _ mutex _ destroy (pthread _ mutex _ t * mutex ) )。
销毁互斥时,必须释放使用的资源,并且当前已打开该锁。 在Linux上,互斥锁不占用资源,因此LinuxThreads中的pthread_mutex_destroy ()除了检查锁定状态外没有其他操作)在锁定状态下返回EBUSY。
2 .独占锁定属性
互斥锁的属性是在创建锁时指定的。 在LinuxThreads实现中,锁定类型只有一个属性,尝试锁定已锁定的互斥锁时,不同的锁定类型的行为不同。 当前(glibc2.2.3,linuxthreads0.9 )具有以下四个值:
* PTHREAD_MUTEX_TIMED_NP,这是默认值,即普通锁。 线程锁定后,请求其馀锁定的线程将形成队列,并在解除锁定后根据优先级获得锁定。 这个锁定策略保证了资源分配的公平性。
* PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁允许同一线程多次成功获取同一锁,并通过多次unlock解锁。 如果是不同线程的请求,则在解除锁定时会重新冲突。
* PTHREAD_MUTEX_ERRORCHECK_NP,检测锁,如果同一线程请求了同一锁,则返回EDEADLK。 否则,其行为与PTHREAD_MUTEX_TIMED_NP类型相同。 这可以确保在不允许多次锁定的情况下,在最简单的情况下不会发生死锁。
* PTHREAD_MUTEX_ADAPTIVE_NP,适应锁定,动作最简单的锁定类型,等待锁定解除后再重新竞争。
3 .锁定操作
锁定操作主要包括pthread_mutex_lock ()、pthread_mutex_unlock () )、测试锁定pthread_mutex_trylock ()等三个操作错误检测锁在解锁者不解除锁定时无效,否则返回EPERM; 嵌套锁的情况下,文件和实现的要求锁定者必须解除锁定,但实验结果没有这样的限制,这个差异现在还没有被说明。 对于同一进程中的线程,如果在不解除锁定的情况下解除锁定,其他线程将无法获取锁定。
int pthread _ mutex _ lock (pthread _ mutex _ t * mutex ) )。
int pthread _ mutex _ unlock (pthread _ mutex _ t * mutex ) )。
int pthread _ mutex _ trylock (pthread _ mutex _ t * mutex ) )是
pthread_mutex_trylock ()语义与pthread_mutex_lock ()语义类似,不同之处在于如果锁已经被占用,则返回EBUSY而不是挂起。
/*=======================================================================================
bufsem.c
功能:主进程负责写入队列(两个元素)的数据,创建的两个线程负责读取数据。
同步排他:主进程和线程之间通过信号量sem_t同步,线程之间通过排他锁进行排他操作。
问题:进程和线程都使用信号量,是否可以解除互斥锁?
注:直接编译gcc -o bufsem bufsem.c会导致以下错误
统一参考至` SEM _ init '
统一参考至` SEM _ post '
统一参考为` SEM _ wait '
您需要在编译选项中添加多线程
gcc -pthread -o bufsem bufsem.c
*/=====================*====*==================*============*======================* * * * * *
#include #i
nclude #include #include #include #include#define N 2 //队列中元素的数量
struct _buf_
{
char *buf[N];
int front, rear; //有from和rear,显然是个队列
}BUF;
void * thread_function_r(void *arg); //线程函数
/*
信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:
extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));
__sem为指向信号量结构的一个指针;__pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;__value给出了信号量的初始值。
*/
sem_t sem_r, sem_w; //semphore,信号量,本程序用于保证进程和线程间的同步
pthread_mutex_t mutex; //互斥锁,保证线程访问的互斥,步骤一,定义数据类型
int main(int argc, char *argv[])
{
int res;
pthread_t a_thread_r, b_thread_r; //线程ID变量,与进程类似,进程为pid_t
for (res=0; resBUF.rear = BUF.front = 0;
/*信号量用sem_init函数创建的,下面是它的说明:
#includeint sem_init (sem_t *sem, int pshared, unsigned int value);
这个函数的作用是对由sem指定的信号量进行初始化,设置好它的共享选项,并指定一个整数类型的初始值。pshared参数控制着信号量的类型。如果 pshared的值是0,就表示它是当前里程的局部信号量;否则,其它进程就能够共享这个信号量。
*/
res = sem_init(&sem_r, 0, 0);
if ( res != 0)
{
perror(strerror(errno));
exit(EXIT_FAILURE);
}
res = sem_init(&sem_w, 0, 2);
if ( res != 0)
{
perror(strerror(errno));
exit(EXIT_FAILURE);
}
if ( pthread_mutex_init(&mutex, NULL) != 0 ) //互斥锁,保证线程访问的互斥,步骤二,初始化,默认属性初始化互斥量——NULL参数的功能
{
perror(strerror(errno));
exit(EXIT_FAILURE);
}
/*
#includeint pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr,void*(*start_rtn)(void*),void *restrict arg);
返回值:若成功则返回0,否则返回出错编号
返回成功时,由tidp指向的内存单元被设置为新创建线程的线程ID。attr参数用于制定各种不同的线程属性。新创建的线程从start_rtn函数的地址开始运行,该函数只有一个无类型指针参数arg,如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg的参数传入。
*/
res = pthread_create(&a_thread_r, NULL, thread_function_r, NULL); //创建读取线程一
if ( res != 0 )
{
perror(strerror(errno));
exit(EXIT_FAILURE);
}
res = pthread_create(&b_thread_r, NULL, thread_function_r, NULL); //创建读取线程二
if ( res != 0 )
{
perror(strerror(errno));
exit(EXIT_FAILURE);
}
while(1) //【功能】主进程执行写入操作
{
sem_wait(&sem_w); //函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。函数sem_destroy(sem_t *sem)用来释放信号量sem。
fputs("Input any words, its words must less than 30: ", stdout);
fgets(BUF.buf[BUF.rear], 30, stdin);
if (strcmp("endn", BUF.buf[(BUF.front) % N]) == 0 ) break;
BUF.rear = (BUF.rear + 1) % N;
sem_post(&sem_r); //函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不再阻塞,选择机制同样是由线程的调度策略决定的。
usleep(1);
}
return 0;
}
void * thread_function_r(void *arg) //【功能】线程负责读取
{
while(1)
{
sem_wait(&sem_r);
pthread_mutex_lock(&mutex); //获取互斥量(互斥锁),另外有pthread_mutex_trylock尝试对互斥量加锁,如果失败返回EBUSY
fprintf(stdout, "Print:BUF.buf[%d] by %u: %s", BUF.front,pthread_self(), BUF.buf[BUF.front]);
BUF.front = (BUF.front + 1) % N;
pthread_mutex_unlock(&mutex); //释放互斥锁
sem_post(&sem_w);
}
}