SYSTEM:
Linux ubuntu 3.2.0-57-generic-pae #87-Ubuntu i686 i686 i386 GNU/Linux
下面是一个简单的实现两个线程之间的原子性,我无法观察
mutex_example.c
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
pthread_mutex_t mut;
void* routine(void* ptr)
{
int ret;
sleep(1);
pthread_detach(pthread_self());
ret=pthread_mutex_lock(&mut);
if(ret!=0)
perror("mutex lock at t1\n");
printf("Thread1 CC\n");
ret=pthread_mutex_unlock(&mut);
if(ret!=0)
perror("mutex unlock at t1\n");
}
int
main(void)
{
int ret;
pthread_t tid;
char* string="hello";
ret=pthread_create(&tid,NULL,routine,string);
if(ret!=0)
perror("thread Creation\n");
ret=pthread_mutex_init(&mut,NULL);//mutex init
if(ret!=0)
perror("mutex Init at main thread\n");
ret=pthread_mutex_lock(&mut);
if(ret!=0)
perror("mutex lock at main thread\n");
printf("before 10sec sleep in main thread\n");
sleep(10);
printf("after 10sec sleep in main thread\n");
ret=pthread_mutex_unlock(&mut);
if(ret!=0)
perror("mutex unlock at main thread\n");
}
预期输出 如果主线程首先启动
before 10sec sleep in main thread
after 10sec sleep in main thread
Thread1 CC
观察到的输出:
before 10sec sleep in main thread
Thread1 CC
after 10sec sleep in main thread
为什么在看到一个锁定时已经锁定的互斥锁应该阻塞直到它解锁,在某种意义上它甚至不能作为信号量工作,而我还尝试了另外一个解锁的东西,但原则上是一个互斥锁可以通过相同的过程锁定和解锁我错过了一些像属性???
EDIT1 :
使用命令gcc -v -o example example.c -lpthread
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.6/lto-wrapper
Target: i686-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu
Thread model: posix
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
COLLECT_GCC_OPTIONS='-v' '-o' 'example' '-mtune=generic' '-march=i686'
/usr/lib/gcc/i686-linux-gnu/4.6/cc1 -quiet -v -imultilib . -imultiarch i386-linux-gnu example.c -quiet -dumpbase example.c -mtune=generic -march=i686 -auxbase example -version -fstack-protector -o /tmp/cczkbCP4.s
GNU C (Ubuntu/Linaro 4.6.3-1ubuntu5) version 4.6.3 (i686-linux-gnu)
compiled by GNU C version 4.6.3, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/i386-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/i686-linux-gnu/4.6/../../../../i686-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/i686-linux-gnu/4.6/include
/usr/local/include
/usr/lib/gcc/i686-linux-gnu/4.6/include-fixed
/usr/include/i386-linux-gnu
/usr/include
End of search list.
GNU C (Ubuntu/Linaro 4.6.3-1ubuntu5) version 4.6.3 (i686-linux-gnu)
compiled by GNU C version 4.6.3, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 09c248eab598b9e2acb117da4cdbd785
COLLECT_GCC_OPTIONS='-v' '-o' 'example' '-mtune=generic' '-march=i686'
as --32 -o /tmp/ccUe328u.o /tmp/cczkbCP4.s
COMPILER_PATH=/usr/lib/gcc/i686-linux-gnu/4.6/:/usr/lib/gcc/i686-linux-gnu/4.6/:/usr/lib/gcc/i686-linux-gnu/:/usr/lib/gcc/i686-linux-gnu/4.6/:/usr/lib/gcc/i686-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.6/:/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/:/usr/lib/gcc/i686-linux-gnu/4.6/../../../../lib/:/lib/i386-linux-gnu/:/lib/../lib/:/usr/lib/i386-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/i686-linux-gnu/4.6/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-o' 'example' '-mtune=generic' '-march=i686'
/usr/lib/gcc/i686-linux-gnu/4.6/collect2 --sysroot=/ --build-id --no-add-needed --as-needed --eh-frame-hdr -m elf_i386 --hash-style=gnu -dynamic-linker /lib/ld-linux.so.2 -z relro -o example /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crti.o /usr/lib/gcc/i686-linux-gnu/4.6/crtbegin.o -L/usr/lib/gcc/i686-linux-gnu/4.6 -L/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu -L/usr/lib/gcc/i686-linux-gnu/4.6/../../../../lib -L/lib/i386-linux-gnu -L/lib/../lib -L/usr/lib/i386-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/i686-linux-gnu/4.6/../../.. /tmp/ccUe328u.o -lpthread -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i686-linux-gnu/4.6/crtend.o /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crtn.o
编辑2:
识别出实现错误:线程是在互斥锁初始化之前创建的
更新:
1。detach
在新形成的线程中删除(而主线程使用join
)
2.改变目标:新创建的线程尝试unlock
mutex
由主线程获取的mutex
(以测试#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
pthread_mutex_t mut;
void* routine(void* ptr)
{
int ret;
sleep(1);
ret=pthread_mutex_unlock(&mut);
if(ret!=0)
perror("mutex lock at t1\n");
printf("Thread1 CC\n");
}
int
main(void)
{
int ret;
pthread_t tid;
char* string="hello";
ret=pthread_mutex_init(&mut,NULL);//mutex init
if(ret!=0)
perror("mutex Init at main thread\n");
ret=pthread_create(&tid,NULL,routine,string);
if(ret!=0)
perror("thread Creation\n");
ret=pthread_mutex_lock(&mut);
if(ret!=0)
perror("mutex lock at main thread\n");
printf("before 10sec sleep in main thread\n");
sleep(10);
printf("after 10sec sleep in main thread\n");
ret=pthread_mutex_unlock(&mut);
if(ret!=0)
perror("mutex unlock at main thread\n");
pthread_join(tid,NULL);
}
功能)新线程应该在哪个等待状态为主线程在10秒睡眠后释放锁定
before 10sec sleep in main thread
Thread1 CC
after 10sec sleep in main thread
观察到的输出:
{{1}}
仍未实现目标!!另一个线程如何解锁主线程获取的互斥锁???
答案 0 :(得分:2)
对于线程,如果给定的线程在#34;长时间内停止运行,它总是值得怀疑的。在两个陈述之间(或序列点,如果我们想要了解它)。
在这种情况下:
如果主线程在创建thread1后停止,则为thread1
可以在互斥锁之前到达pthread_mutex_lock()
初始化。
如果主线程在初始化互斥锁后停止,则在主线程锁定互斥锁之前,thread1可以运行完成。
如果thread1随时停止,并且主线程运行完成,那么整个进程将退出......无论thread1是否准备就绪。
其中(1)和(2)可能是理论上的 - 给定了thread1中的sleep(1)
- 但是当你想要的行为取决于奇数sleep()
时你就知道你遇到了麻烦!另一方面,(3)肯定是令人担忧的原因。
此外,检查所有pthread_xxx()
来电的退货代码是好的,但他们不会设置errno
,因此perror()
会打印一条消息,但赢了&#39 ; t告诉你错误是什么(你需要errno = ret ;
来实现这个目标。)
然而,这并不能解释为什么当主线程显然拥有它时,thread1显然已经获得了互斥锁。
stdio
内容被定义为线程安全的,并且使用行缓冲stdout
并打印完整的行...我也希望输出按预期显示。< / p>
所以...不是一个完整的答案(对不起)......但如果我是你,我会摆脱pthread_detach()
并向主要(在它退出之前)添加pthread_join()
并且看它是否仍然表现得很奇怪。 (并且,为了完整性,在创建thread1之前初始化互斥锁。)
我认为这与-pthread
链接。
我已经尝试了发布的代码,它可以正常工作(3.14.9 Linux内核,x86_64,gcc 4.8.3,glibc 2.18)。 (我得到一个警告,sleep()
被隐含声明......但是这并没有阻止它工作。)所以我不得不得出结论:在编译/链接的方式上有一些麻烦您的机器,或库的某些问题,或其他一些特殊的系统特定问题。
答案 1 :(得分:2)
因此我认为它是真的有一些东西可以在我们使用这种操作时调整互斥锁属性
对于未定义的情况,应该避免三种类型的尝试
pthread_mutex_lock的手册页定义了可以与属性一起使用的互斥锁类型
If the mutex type is PTHREAD_MUTEX_NORMAL, deadlock detection shall not be provided.
Attempting to relock the mutex causes deadlock.If a thread attempts to unlock a mutex
that it has not locked or a mutex which is unlocked, undefined behavior results.
If the mutex type is PTHREAD_MUTEX_ERRORCHECK, then error checking shall be provided.
If a thread attempts to relock a mutex that it has already locked, an error shall
be returned. If a thread attempts to unlock a mutex that it has not locked or a mutex
which is unlocked, an error shall be returned.
If the mutex type is PTHREAD_MUTEX_RECURSIVE, then the mutex shall maintain the concept
of a lock count. When a thread successfully acquires a mutex for the first time, the
lock count shall be set to one. Every time a thread relocks this mutex, the lock count
shall be incremented by one. Each time the thread unlocks the mutex, the lock count
shall be decremented by one. When the lock count reaches zero, the mutex shall become
available for other threads to acquire. If a thread attempts to unlock a mutex that it
has not locked or a mutex which is unlocked, an error shall be returned.
If the mutex type is PTHREAD_MUTEX_DEFAULT, attempting to recursively lock the mutex
results in undefined behavior. Attempting to unlock the mutex if it was not locked
by the calling thread results in undefined behavior. Attempting to unlock the mutex if
it is not locked results in undefined behavior.
所以我应该提供PTHREAD_MUTEX_ERRORCHECK
的属性来检查不是由它拥有的互斥锁是否被解锁,如果这样做,那么使用errno进行检查是EPERM
你可以利用pthread_mutexattr_xx函数设置和初始化下面的atributes代码可能有帮助
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<errno.h>
pthread_mutex_t mut;
void* routine(void* ptr)
{
int ret;
//sleep(4);
ret=pthread_mutex_unlock(&mut);
if(ret!=0)
{
errno=ret;
perror("mutex unlock at t1\n");
if(errno==EPERM)
pthread_mutex_lock(&mut);
}
fprintf(stderr,"Thread1 CC\n");
//pthread_mutex_unlock(&mut);
}
int
main(void)
{
int ret;
pthread_t tid;
char* string="hello";
pthread_mutexattr_t attr;
ret=pthread_mutexattr_init(&attr);//mutex attr init
if(ret!=0)
{
errno=ret;
perror("mutex attr Init at main thread\n");
}
ret=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ERRORCHECK);//mutex typeset
if(ret!=0)
{
errno=ret;
perror("mutex typeset Init at main thread\n");
}
ret=pthread_mutex_init(&mut,&attr);//mutex init
if(ret!=0)
{
errno=ret;
perror("mutex Init at main thread\n");
}
ret=pthread_mutexattr_destroy(&attr);//attr no longer needed
if(ret!=0)
{
errno=ret;
perror("mutex attr destory at main thread\n");
}
ret=pthread_create(&tid,NULL,routine,string);
if(ret!=0)
{
errno=ret;
perror("thread Creation\n");
}
ret=pthread_mutex_lock(&mut);
if(ret!=0)
{
errno = ret;
perror("mutex lock at main thread\n");
}
fprintf(stderr,"before 10sec sleep in main thread\n");
sleep(10);
fprintf(stderr,"after 10sec sleep in main thread\n");
ret=pthread_mutex_unlock(&mut);
if(ret!=0)
{
errno = ret;
perror("mutex unlock at main thread\n");
}
pthread_join(tid,NULL);
}
请注意,主要目标是查看互斥锁的行为,当其被非特定互斥锁的所有者锁定或解锁时,在edit2和最终答案中分别对任何版本进行了解析