posix多线程编程,posix线程库
多线程程序中同步访问的另一种方法是互斥,它允许程序锁定一个对象,以便只有一个线程可以访问它。为了控制对临界区代码的访问,在我们进入这段代码之前锁定一个互斥体,当我们完成操作时解锁它。
使用互斥所需的基本函数类似于信号量所需的函数,它们的声明如下:
#include pthread.h
int pthread _ mutex _ init(pthread _ mutex _ t * mutex,const pthread_mutexattr_t
* mutexattr);
int pthread _ mutex _ lock(pthread _ mutex _ t * mutex);
int pthread _ mutex _ unlock(pthread _ mutex _ t * mutex);
int pthread _ mutex _ destroy(pthread _ mutex _ t * mutex);
像往常一样,成功时返回0,失败时返回错误代码,但errno未设置;我们必须使用返回代码。
类似于信号量,这些函数以一个指向之前声明的对象的指针作为参数,互斥的方法是pthread _ mutex _ t,额外的属性参数pthread_mutexattr_t允许我们为互斥提供属性,可以控制它的行为。该属性默认为“快速”。这有一个小缺点。如果我们的程序试图在一个已经锁定的互斥体上调用pthread_mutex_lock,程序将会阻塞。因为拥有锁的线程现在被阻塞了,互斥体将不会被解锁,程序将进入死锁状态。您可以修改互斥体的属性,这样他就可以检测到这种情况并返回一个错误,或者循环并允许在同一个线程上有多个锁。
设置互斥属性超出了本书的范围,所以我们将为属性指针传递NULL并使用默认行为。我们可以阅读pthread_mutex_init手册页来了解修改属性的内容。
实验线程互斥
同样,下面的程序是我们的原始程序thread1.c的修改版本,但是做了很多修改。这一次,我们有些偏执地访问我们的关键变量,并使用一个互斥体来确保一次只有一个线程访问它们。为了使代码更容易阅读,我们忽略了对互斥锁和解锁操作返回值的错误检测。在生产代码中,我们应该检查这些返回值。这是一个新程序,thread4.c:
#包含stdio.h
#包含stdlib.h
#包括unistd.h
#包含字符串. h
#include pthread.h
#包含信号量. h
void * thread _ function(void * arg);
pthread _ mutex _ t work _ mutex
#定义工作大小1024
char WORK _ area[WORK _ SIZE];
int time _ to _ exit=0;
int main()
{
int res
pthread _ t a _ thread
void * thread _ result
RES=pthread _ mutex _ init(work _ mutex,NULL);
if(res!=0)
{
perror(互斥初始化失败);
退出(EXIT _ FAILURE);
}
res=pthread_create( a_thread,NULL,thread_function,NULL);
if(res!=0)
{
perror(“线程创建失败”);
退出(EXIT _ FAILURE);
}
pthread _ mutex _ lock(work _ mutex);
printf(输入一些文字,输入 end 结束/n );
而(!离开的时间)
{
fgets(work_area,WORK_SIZE,stdin);
pthread _ mutex _ unlock(work _ mutex);
while(1)
{
pthread _ mutex _ lock(work _ mutex);
if(work_area[0]!=/0)
{
pthread _ mutex _ unlock(work _ mutex);
睡眠(1);
}
其他
{
打破;
}
}
}
pthread _ mutex _ unlock(work _ mutex);
printf(/n等待线程完成./n’);
res=pthread_join(a_thread,thread _ result);
if(res!=0)
{
perror(“线程加入失败”);
退出(EXIT _ FAILURE);
}
printf(螺纹连接/n );
pthread _ mutex _ destroy(work _ mutex);
退出(EXIT _ SUCCESS);
}
void *thread_function
{
睡眠(1);
pthread _ mutex _ lock(work _ mutex);
while(strncmp(end ,work_area,3)!=0)
{
printf(您输入了%d个字符/n ,strlen(work _ area)-1);
work _ area[0]=/0 ;
pthread _ mutex _ unlock(work _ mutex);
睡眠(1);
pthread _ mutex _ lock(work _ mutex);
while(work_area[0]==/0 )
{
pthread _ mutex _ unlock(work _ mutex);
睡眠(1);
pthread _ mutex _ lock(work _ mutex);
}
}
时间到退出=1;
work _ area[0]=/0 ;
pthread _ mutex _ unlock(work _ mutex);
pthread _ exit(0);
}
$ cc-D _ REENTRANT-I/usr/include/nptl thread 4 . co thread 4-L/usr/lib/nptl-
线程库
$ ./线程4
输入一些文本。输入“结束”结束
一点点
你输入4个字符
拥挤的道路
你输入13个字符
目标
正在等待线程完成.
螺纹连接
我们开始声明一个互斥体,我们的工作空间,这一次,我们声明了一个额外的变量:time_to_exit。
pthread _ mutex _ t work _ mutex/*保护工作区和退出时间*/
#定义工作大小1024
char WORK _ area[WORK _ SIZE];
int time _ to _ exit=0;
然后我们初始化互斥体。
RES=pthread _ mutex _ init(work _ mutex,NULL);
if (res!=0) {
perror("互斥初始化失败");
退出(EXIT _ FAILURE);
}
接下来,我们开始我们的新线程。下面是在线程函数中执行的代码:
pthread _ mutex _ lock(work _ mutex);
while(strncmp("end ",work_area,3)!=0) {
printf("你输入了%d个字符/n ",strlen(work _ area)-1);
work _ area[0]=/0 ;
pthread _ mutex _ unlock(work _ mutex);
睡眠(1);
pthread _ mutex _ lock(work _ mutex);
while (work_area[0]==/0 ) {
pthread _ mutex _ unlock(work _ mutex);
睡眠(1);
pthread _ mutex _ lock(work _ mutex);
}
}
时间到退出=1;
work _ area[0]=/0 ;
pthread _ mutex _ unlock(work _ mutex);
首先,新线程试图锁定这个互斥体。如果它已经被锁定,调用将被阻塞,直到互斥体被释放。一旦我们访问,我们检查是否我们被要求退出。如果要求我们退出,我们只需设置退出时间,清除工作区中的第一个字符,然后退出。
如果我们不想退出,我们计算字符数,然后清空第一个字符。我们使用清除第一个字符的方法来通知读者我们已经完成了计算。然后我们解锁互斥体,等待主线程运行。我们将循环尝试锁定这个互斥体,当我们成功时,我们将检查主线程是否指定了更多的工作给我们去做。如果没有,我们解锁互斥体并等待更长的时间。如果是这样,我们计算字符数并再次进入循环。
这里是主线:
pthread _ mutex _ lock(work _ mutex);
printf("输入一些文本。输入 end 结束/n ");
而(!时间到退出){
fgets(work_area,WORK_SIZE,stdin);
pthread _ mutex _ unlock(work _ mutex);
while(1) {
pthread _ mutex _ lock(work _ mutex);
if (work_area[0]!=/0) {
pthread _ mutex _ unlock(work _ mutex);
睡眠(1);
}
否则{
打破;
}
}
}
pthread _ mutex _ unlock(work _ mutex);
这类似于上面提到的线程。我们锁定工作区,以便我们可以将文本读入其中,然后解锁它以允许其他线程访问它来计算字数。循环往复,我们重新锁定互斥体,检查是否已经计算出字数,如果需要等待更长时间,我们就会释放这个锁。正如我们前面提到的,这不是一个好的编程习惯,在现实世界中,我们可以使用信号量来避免这种情况。但是,这里的代码仅用作示例。