首页 > 编程知识 正文

读写锁和互斥锁的区别,linux自旋锁和互斥锁

时间:2023-05-06 13:28:02 阅读:110732 作者:874

使用互斥锁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);

}

}

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。