您的位置:首页 > 运维架构 > Linux

浅谈Linux多线程编程和Windows多线程编程的异同

2013-10-29 17:03 701 查看
对于linux操作系统,互斥也是类似的,只是函数不同罢了。在linux下,和互斥相关的几个函数也要闪亮登场了。
               pthread_mutex_init函数:初始化一个互斥锁;
               pthread_mutex_destroy函数:注销一个互斥锁;
               pthread_mutex_lock函数:加锁,如果不成功,阻塞等待;
               pthread_mutex_unlock函数:解锁;
                pthread_mutex_trylock函数:测试加锁,如果不成功就立即返回,错误码为EBUSY;
    至于这些函数的用法,google上一搜,就出来了,呵呵,在这里不多讲了。windows下还有一个可以用来保护数据的方法,也是线程同步的方式
就是临界区了。临界区和互斥类似。它们之间的区别是,临界区速度快,但是它只能用来同步同一个进程内的多个线程。临界区的获取和释放函数如下:
EnterCriticalSection() 进入临界区; LeaveCriticalSection()离开临界区。 对于多线程共享内存的东东就讲到这里了。
 
  (2)采用消息机制进行多线程通信和同步,windows下面的的消息机制的函数用的多的就是postmessage了。Linux下的消息机制,我用的较少,就不在这里说了,如果谁熟悉的,也告诉我,呵呵。
 
(3)windows下的另外一种线程通信方法就是事件和信号量了。同样针对我开始举得例子,2个线程同步,他们之间传递信息,可以采用事件(Event)或信号量(Semaphore),比如第一个线程完成生产的数据后,就必须告诉第2个线程,他已经把数据准备好了,你可以来取走了。第2个线程就把数据取走。呵呵,这里可以采用消息机制,当第一个线程准备好数据后,就直接postmessage给第2个线程,按理说采用postmessage一个线程就可以搞定这个问题了。呵呵,不是重点,省略不讲了。
对于linux,也有类似的方法,就是条件变量了,呵呵,这里windows和linux就有不同了。要特别讲讲才行。
对于windows,采用事件和信号量同步时候,都会使用waitforsingleobject进行等待的,这个函数的第一个参数是一个句柄,在这里可以是Event句柄,或Semaphore句柄,第2个参数就是等待的延迟,最终等多久,单位是ms,如果这个参数为INFINITE,那么就是无限等待了。释放信号量的函数为ReleaseSemaphore();释放事件的函数为SetEvent。当然使用这些东西都要初始化的。这里就不讲了。Msdn一搜,神马都出来了,呵呵。神马都是浮云!
对于linux操作系统,是采用条件变量来实现类似的功能的。Linux的条件变量一般都是和互斥锁一起使用的,主要的函数有:
pthread_mutex_lock ,
pthread_mutex_unlock,
pthread_cond_init
pthread_cond_signal
pthread_cond_wait
pthread_cond_timewait
为了和windows操作系统进行对比,我用以下表格进行比较:
      
对象
操作
Linux
Windows
线程
创建
Pthread_create
CreateThread/Afxbeginthread
退出
Pthread_exit
ThreadExit
等待
Pthread_join
WaitForSingleObject
互斥锁
创建
Pthread_mutex_init
CreateMutex
销毁
Pthread_mutex_destroy
CloseHandle
加锁
Pthread_mutex_lock
WaitForSingleObject
解锁
Pthread_mutex_unlock
ReleaseMutex
条件变量
创建
pthread_cond_init
CreateEvent
销毁
Pthread_cond_destroy
CloseHandle
触发
pthread_cond_signal
SetEvent
广播
Pthread_cond_broadcast
SetEvent/ResetEvent
等待
Pthread_cond_wait
SingleObjectAndWait
Pthread_cond_timedwait
 
 
 
 
Linux专有的
Pthread_cleanup_push:

Pthread_cleanup_pop:
这两个函数用来保护当程序出现异常时,清除资源等。
Windows专有
Semaphore
 
对照以上表格,总结如下:
(1) Pthread_cleanup_push,Pthread_cleanup_pop:
这一对函数push和pop的作用是当出现异常退出时,做一些清除操作,即当在push和pop函数之间异常退出,包括调用pthread_exit退出,都会执行push里面的清除函数,如果有多个push,注意是是栈,先执行后面的那个函数,在执行前面的函数,但是注意当在这2个函数之间通过return 退出的话,执不执行push后的函数就看pop函数中的参数是不是为0了。还有当没有异常退出时,等同于在这里面return退出的情况,即:当pop函数参数不为0时,执行清除操作,当pop函数参数为0时,不执行push函数中的清除函数。
(2)linux的pthread_cond_signal和SetEvent的不同点
Pthread_cond_singal释放信号后,当没有Pthread_cond_wait,信号马上复位了,这点和SetEvent不同,SetEvent是不会复位的。详解如下:
条件变量的置位和复位有2种常用模型:第一种模型是当条件变量置位时(signaled)以后,如果当前没有线程在等待,其状态会保持为置位(signaled),直到有等待的线程进入被触发,其状态才会变为unsignaled,这种模型以采用Windows平台上的Auto-set Event 为代表。
第2种模型则是Linux平台的pthread所采用的模型,当条件变量置位(signaled)以后,即使当前没有任何线程在等待,其状态也会恢复为复位(unsignaled)状态。
条件变量在Linux平台上的这种模型很难说好坏,在实际应用中,我们可以对
代码稍加改进就可以避免这种差异的发生。由于这种差异只会发生在触发没有被线程等待在条件变量的时刻,因此我们只需要掌握好触发的时机即可。最简单的做法是增加一个计数器记录等待线程的个数,在决定触发条件变量前检查该变量即可。
示例  使用 pthread_cond_wait() 和 pthread_cond_signal()
 
pthread_mutex_t count_lock;
pthread_cond_t count_nonzero;
unsigned count;
decrement_count()
{
    pthread_mutex_lock(&count_lock);
    while (count == 0)
        pthread_cond_wait(&count_nonzero, &count_lock);
    count = count - 1;
    pthread_mutex_unlock(&count_lock);
}
 
increment_count()
{
    pthread_mutex_lock(&count_lock);
    if (count == 0)
        pthread_cond_signal(&count_nonzero);
    count = count + 1;
    pthread_mutex_unlock(&count_lock);
 
}
 
(3) 注意Pthread_cond_wait条件返回时互斥锁的解锁问题
extern int pthread_cond_wait __P ((pthread_cond_t *__cond,pthread_mutex_t *__mutex));
 调用这个函数时,线程解开mutex指向的锁并被条件变量cond阻塞。线程可以被函数pthread_cond_signal和函数 pthread_cond_broadcast唤醒线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,一般说来线程应该仍阻塞在这里,被等待被下一次唤醒。如果在多线程中采用pthread_cond_wait来等待时,会首先释放互斥锁,当等待的信号到来时,再次获得互斥锁,因此在之后要注意手动解锁。举例如下:
 
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; /*初始化互斥锁*/
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;  //初始化条件变量
 
void *thread1(void *);
void *thread2(void *);
 
int i=1;
int main(void)
{
        pthread_t t_a;
        pthread_t t_b;
        pthread_create(&t_a,NULL,thread1,(void *)NULL);/*创建进程t_a*/
        pthread_create(&t_b,NULL,thread2,(void *)NULL); /*创建进程t_b*/
        pthread_join(t_b, NULL);/*等待进程t_b结束*/
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&cond);
         exit(0);
}
 
void *thread1(void *junk)
{
        for(i=1;i<=9;i++)
        {
             printf("IN one\n"); 
             pthread_mutex_lock(&mutex);//
           if(i%3==0)
              pthread_cond_signal(&cond);/*,发送信号,通知t_b进程*/
           else      
                  printf("thead1:%d\n",i);
              pthread_mutex_unlock(&mutex);//*解锁互斥量*/
              printf("Up  Mutex\n");     
       sleep(3);
        }
 
}
 
void *thread2(void *junk)
{
        while(i<9)
        {
             printf("IN two \n"); 
              pthread_mutex_lock(&mutex);
            if(i%3!=0)
                   pthread_cond_wait(&cond,&mutex);/*等待*/
            printf("thread2:%d\n",i);
            pthread_mutex_unlock(&mutex);
            printf("Down  Mutex\n");
 
            sleep(3);
 }
 
}
 
输出如下:
IN one
thead1:1
Up  Mutex
IN two
IN one
thead1:2
Up  Mutex
IN one
thread2:3
Down  Mutex
Up  Mutex
IN one
thead1:4
Up  Mutex
IN two
IN one
thead1:5
Up  Mutex
IN one
Up  Mutex
thread2:6
Down  Mutex
IN two
thread2:6
Down  Mutex
IN one
thead1:7
Up  Mutex
IN one
thead1:8
Up  Mutex
IN two
IN one
Up  Mutex
thread2:9
Down  Mutex
 
注意蓝色的地方,有2个thread2:6,其实当这个程序多执行几次,i=3和i=6时有可能多打印几个,这里就是竞争锁造成的了。
引自:http://www.linuxidc.com/Linux/2011-03/33603p2.htm
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: