LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
123
返回列表 发新帖
楼主: elssann

linux下有对某个数字有同步的函数吗?

[复制链接]
发表于 2004-11-10 18:47:22 | 显示全部楼层
即使是用户态的线程,在linux内核看来也同样是进程,内核对它们如何使用cpu,及进程的调度,一视同仁。没有什么线程就一定开销小的说法。
线程之所以被称为轻量级进程,是因为它与父进程运行的地址空间完全一样,甚至是同样的线性区。
所以对于同一个父进程之间线程的某些变量同步的话,不可避免的牵涉到某个轻量级进程的挂起和唤醒。
可是,挂起和唤醒进程都工作在内核态。
请不要夸大线程的作用。
发表于 2004-11-10 19:00:36 | 显示全部楼层
我觉的比较好的用户态的解决方案是共享的变量同步的问题的好办法是,每个轻量级进程在每次改变该变量a值时,通过系统调用把该变量所在的内存页设为只读,如果别的轻量级进程读的话不会出错,但它要写的话,就会出现段错误,然后自己写个信号处理程序,捕捉到该异常信号,通过系统调用把后一个进程挂起。
直到最先的一个进程把该内存页设为可写以后,可以发出一个用户信号唤醒刚被挂起的进程。后一个进程就可以访问该变量了。
发表于 2004-11-10 19:01:33 | 显示全部楼层
这个方法的缺点是,一个变量要占用一个内存页。比较的浪费内存。
发表于 2004-11-11 09:37:31 | 显示全部楼层
最初由 realtang 发表
这个方法的缺点是,一个变量要占用一个内存页。比较的浪费内存。


你所说的解决方案正如你所说的,耗费太大了,肯定是不现实的。

至于线程,linux里用__clone实现的内核线程对于内核来说和普通的进程的确没什么特别大的区别。这是Linux的实现方式导致的。线程库的实现有几种模型,各有各的好处的。

至于Pthread Mutex,并没有规定它一定要是完完全全在用户态的。就像线程一样,很普遍的一种做法是内核有支撑的数据结构(不一定在内核态的),库封装并提供更多和更高级的功能,简单的说它效率低下,我认为是武断的。

2.6的内核里有个叫Fumux(Fast Userspace Mutex)的东东,可以瞧瞧。这个也是NPTL所使用的同步原语。
 楼主| 发表于 2004-11-11 09:50:58 | 显示全部楼层
最初由 kj501 发表
我觉得你只看到了问题的一个方面:
如果是同一进程的不同线程之间的同步,用户态的线程完全可以在用户态实现自己的同步机制,不需要陷入内核态去使用内核提供的信号灯,这种情况在实际应用中是很多的,效率也是很高的;如果是分别属于不同进程的线程之间的同步,这种情况下就需要进程的同步,自然要使用内核的信号灯。多了从用户态到内核态切换的开销,自然效率就要下降了。


确实如此,在《WINDOWS核心编程》作者就提到了这个问题。
能用USER MODE同步方式就尽量用USER MODE同步方式。
凡是同步用到了KERNEL MODE和USER MODE之间切换,至少耗费几千个CPU周期。
在WINDOWS下,Interlocked系列函数,都是用来在USER MODE里对某个数值进行原子操作增加或者减少的函数。
在WINDOWS下,有一个临界区CriticalSection和LINUX下的pthread_mutex_t使用方法是一样的,作用也一样。

在同步方式中,凡是可以让线程或者进程挂起等待的同步方式,肯定必须在USER MODE和KERNEL MODE之间切换。信号灯大多数场合效率都比pthread_mutex_t低,因为凡是信号灯,就必须在USER MODE和KERNEL MODE之间切换。而pthread_mutex_t,每次调用lock的时候,如果此时没有别的线程在使用pthread_mutex_t保护的资源,那么他就不需要挂起,也就无须切换到KERNEL MODE里。只有在别的线程已经lock了,再次想去lock的线程才会切换到KERNEL MODE里去挂起等待。

WINDOWS里面,为了提高同步效率,在对临界区资源的使用中,甚至还提供了一个函数:EnterCriticalSectionAndSpin。可以指定一个int参数,用来指明,当某个线程想去LOCK的时候,如果有别的线程已经先LOCK了,那么这个线程不直接进入内核状态挂起,而是轮训int参数指定的次数,如果在轮训中别的线程UNLOCK了,这个线程就避免了一次KERNEL MODE的切换。只有在轮训完后,别的线程还没UNLOCK,才会切换到内核模式挂起。由此可以见,USER MODE和KERNEL MODE的切换效率损失是很大的。 WINDOWS系统本身用的对堆栈保护的轮训次数是4000次。
虽然是不同的操作系统,但是我想有很大的参考价值。
发表于 2004-11-11 22:04:01 | 显示全部楼层
最初由 realtang 发表
即使是用户态的线程,在linux内核看来也同样是进程,内核对它们如何使用cpu,及进程的调度,一视同仁。没有什么线程就一定开销小的说法。

我认为你对用户态的线程模型有误解。用户态的线程是在用户态实现的,对于内核来说,它根本就感觉不到线程的存在。它只能把属于同一进程的几个线程当作是一个进程来看待,至于这些线程的创建和退出,几个线程正常运行,又有几个正在等待等等调度方面的问题,内核根本就不参与,而是让线程自己去处理。正因为如此,用户态的线程才可以在不支持线程的操作系统上实现。“即使是用户态的线程,在linux内核看来也同样是进程”这句话说得很不准确。内核并不是把每个用户态线程都当作一个进程去调度的。假如说有两个进程A和B,进程A有两个线程A1和A2,进程B有三个线程B1、B2、B3。内核只调度A和B两个进程,而不是直接去调度A1、A2、B1、B2、B3这五个线程。至于线程间的调度(以单CPU的计算机为例),当内核让进程A运行时(此时进程B等待),再由进程A决定是线程A1运行还是线程A2运行,同理,当进程A等待,而进程B运行时,再由B决定B1、B2、B3中那一个运行。内核当然可以介入到每一个用户态线程的调度中去。但那样做,是一种低效率的做法。
linux的POSIX线程实现采用了与进程相类似的做法。你可以受到这个影响很深。
这种实现差不多快要把线程当成进程来调度了。比如说用ps命令,可以看到每个线程的ID号。虽然这与我所说的理论可能有一些出入,但这只是特例,不是通常的情况。其它操作系统上的用户态线程实现,都不是这样的。
线程之所以被称为轻量级进程,是因为它与父进程运行的地址空间完全一样,甚至是同样的线性区。
所以对于同一个父进程之间线程的某些变量同步的话,不可避免的牵涉到某个轻量级进程的挂起和唤醒。
可是,挂起和唤醒进程都工作在内核态。
请不要夸大线程的作用。

我前面也说过了,用户态的线程可以实现自己的同步机制。只有在需要与其它进程进行同步时,才需要内核参与。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表