多线程和互斥量


在单核处理器上, 内核使用时间分片来模拟线程的并发执行;在多核处理器上,线程与进程一样,可以并发执行。

两种软件运行模式:单进程/多线程模式,非多进程/单线程模式。为什么使用线程不使用进程?进程间通信(IPC)困难。每个进程拥有独自的内存空间,而线程共享相同的内存空间。http://blog.csdn.net/zmxiangde_88/article/details/7998458


Liunx线程基本函数

#include <pthread.h>

1.线程创建:

int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

参数说明:

thread:指向pthread_create类型的指针,用于引用新创建的线程。

attr:用于设置线程的属性,一般不需要特殊的属性,所以可以简单地设置为NULL。

*(*start_routine)(void *):传递新线程所要执行的函数地址。

arg:新线程所要执行的函数的参数。

调用如果成功,则返回值是0,如果失败则返回错误代码。

2.线程终止

void pthread_exit(void *retval);

参数说明:

retval:返回指针,指向线程向要返回的某个对象。

线程通过调用pthread_exit函数终止执行,并返回一个指向某对象的指针。注意:绝不能用它返回一个指向局部变量的指针,因为线程调用该函数后,这个局部变量就不存在了,这将引起严重的程序漏洞。

3.线程同步

int pthread_join(pthread_t th, void **thread_return);

参数说明:

th:将要等待的线程。

thread_return:线程的返回值。


互斥体(mutex,mutual exclusion的缩写)。一个互斥体一次只允许一个线程访问共享区。当一个线程想要访问共享区时,首先要做的就是锁住(lock)互斥体。如果其他的线程已经锁住了互斥体,那么就必须先等那个线程将互斥体解锁,这样就保证了同一时刻只有一个线程能访问共享区域。

Boost线程库支持两大类互斥体,包括简单互斥体(simple mutex)和递归互斥体(recursive mutex)。如果同一个线程对互斥体上了两次锁,就会发生死锁(deadlock),也就是说所有的等待解锁的线程将一直等下去。有了递归互斥体,单个线程就可以对互斥体多次上锁,当然也必须解锁同样次数来保证其他线程可以对这个互斥体上锁。

在这两大类互斥体中,对于线程如何上锁还有多个变种。一个线程可以有三种方法来对一个互斥体加锁:

  1. 一直等到没有其他线程对互斥体加锁。
  2. 如果有其他互斥体已经对互斥体加锁就立即返回。
  3. 一直等到没有其他线程互斥体加锁,直到超时。
boost::mutex,
boost::try_mutex,
boost::timed_mutex,
boost::recursive_mutex,
boost::recursive_try_mutex,
boost::recursive_timed_mutex

  1. boost::mutex::scoped_lock lock(mutex_);  
  2. cond_.wait(lock);  
这两行代码,第一行锁定mutex_对象。第二行代码首先解开这个mutex_上的锁(为了其它线程能够使用该mutex_),然后进行等待,直到其它线程在该条件变量上调用notify_one()或者notify_all()函数。条件变量为真后,第二行代码尝试给mutex_上锁。
cond_.notify_all函数,通知那些所有正在等待cond_条件变量变为真的线程,那些线程随后进入运行状态。

fast_mutex.hpp中定义了跨平台的简单易用的互斥量。
代码来源于https://sourceforge.net/projects/nvwa/
#ifdef WIN32

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
class fast_mutex
{
private:
    CRITICAL_SECTION _M_mtx_impl;
public:
    fast_mutex()
    {
        ::InitializeCriticalSection(&_M_mtx_impl);
    }
    ~fast_mutex()
    {
        ::DeleteCriticalSection(&_M_mtx_impl);
    }
    void lock()
    {
        ::EnterCriticalSection(&_M_mtx_impl);
    }
    bool trylock()
    {
        if (::TryEnterCriticalSection(&_M_mtx_impl)) {
            return true;
        }else{
            return false;
        }
    }
    void unlock()
    {
        ::LeaveCriticalSection(&_M_mtx_impl);
    }
private:
    // 禁止拷贝构造函数和赋值构造函数
    fast_mutex(const fast_mutex&);
    fast_mutex& operator=(const fast_mutex&);
};

#else // for Linux

#include <pthread.h>
class fast_mutex
{
private:
    pthread_mutex_t _M_mtx_impl;
    pthread_mutexattr_t _M_mtx_attr;
public:
    fast_mutex()
    {
        ::pthread_mutexattr_init(&_M_mtx_attr);
        ::pthread_mutexattr_settype(&_M_mtx_attr, PTHREAD_MUTEX_RECURSIVE);
        ::pthread_mutex_init(&_M_mtx_impl, &_M_mtx_attr);
    }
    ~fast_mutex()
    {
        ::pthread_mutex_destroy(&_M_mtx_impl);
        ::pthread_mutexattr_destroy(&_M_mtx_attr);
    }
    void lock()
    {
        ::pthread_mutex_lock(&_M_mtx_impl);
    }
    bool trylock()
    {
        if (::pthread_mutex_trylock(&_M_mtx_impl)) {
            return true;
        } else {
            return false;
        }
    }
    void unlock()
    {
        ::pthread_mutex_unlock(&_M_mtx_impl);
    }
private:
    // 禁止拷贝构造函数和赋值构造函数
    fast_mutex(const fast_mutex& );
    fast_mutex& operator=(const fast_mutex&);
};

#endif // end for WIN32




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会尽力回答你的问题。首先,哲学家进餐问题是一个经典的多线程同步问题,其描述如下: 有五位哲学家,围坐在一张圆桌周围,他们的生活方式只有思考和进餐。在圆桌上有五个餐具,每两个相邻的哲学家之间放置一把餐叉。哲学家进餐时需要同时拿到他左右两个餐叉,才能进餐。当一个哲学家进餐结束后,他会放下手中的餐叉,然后继续思考。请设计一个程序,使得每个哲学家都能够进餐,但不会出现死锁或饥饿状态。 在Linux系统中,我们可以使用POSIX API来实现多线程互斥机制。具体来说,我们可以使用pthread_create函数创建多个线程,每个线程代表一个哲学家。在每个线程中,我们可以使用pthread_mutex_lock和pthread_mutex_unlock函数来实现互斥机制,保证每个哲学家在进餐时只能同时拿到他左右两个餐叉。 下面是一个基于POSIX API的哲学家进餐问题的代码实现: ```c #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define NUM_PHILOSOPHERS 5 #define LEFT (i + NUM_PHILOSOPHERS - 1) % NUM_PHILOSOPHERS #define RIGHT (i + 1) % NUM_PHILOSOPHERS pthread_mutex_t chopstick[NUM_PHILOSOPHERS]; void *philosopher(void *arg) { int i = *(int *)arg; while (1) { printf("Philosopher %d is thinking...\n", i); sleep(rand() % 5); printf("Philosopher %d is hungry...\n", i); pthread_mutex_lock(&chopstick[LEFT]); pthread_mutex_lock(&chopstick[RIGHT]); printf("Philosopher %d is eating...\n", i); sleep(rand() % 5); pthread_mutex_unlock(&chopstick[RIGHT]); pthread_mutex_unlock(&chopstick[LEFT]); } return NULL; } int main() { pthread_t tid[NUM_PHILOSOPHERS]; int i, id[NUM_PHILOSOPHERS]; for (i = 0; i < NUM_PHILOSOPHERS; ++i) { pthread_mutex_init(&chopstick[i], NULL); } for (i = 0; i < NUM_PHILOSOPHERS; ++i) { id[i] = i; pthread_create(&tid[i], NULL, philosopher, &id[i]); } for (i = 0; i < NUM_PHILOSOPHERS; ++i) { pthread_join(tid[i], NULL); } for (i = 0; i < NUM_PHILOSOPHERS; ++i) { pthread_mutex_destroy(&chopstick[i]); } return 0; } ``` 在这个程序中,我们首先定义了一个长度为5的互斥数组,用于表示五个餐叉。然后,我们使用pthread_create函数创建了五个线程,每个线程代表一个哲学家。在每个线程中,我们使用pthread_mutex_lock和pthread_mutex_unlock函数来实现互斥机制,保证每个哲学家在进餐时只能同时拿到他左右两个餐叉。最后,我们使用pthread_join函数等待所有线程结束,并释放互斥资源。 希望这个代码可以帮助你理解如何利用POSIX API在Linux系统上,通过多线程互斥机制实现哲学家进餐问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值