线程同步对象的实现

struct futex {
	volatile int lock;
	volatile int count;
};

#define LARGE_ENOUGH_NEGATIVE			-0x7fffffff

#ifdef	__cplusplus
extern "C" {
#endif

static inline void
futex_init(struct futex* pf, int count)
{
	pf->lock = 0;
	pf->count = count;
}

/* Return value:
 *         0: okay
 * ETIMEDOUT: timeout
 *     EINTR: interrupted
 */
static inline int 
futex_sema_down(struct futex* pf, struct timespec* timeout, bool interruptable)
{
	int n = atomic_add(&pf->count, -1);
	if (n <= 0) {
retry:
        if (0 == sys_futex(&pf->lock, FUTEX_WAIT, 0, timeout)) {
			return 0;
        }

		switch (errno) {
		case ETIMEDOUT: 
			atomic_add(&pf->count, 1); 
			return ETIMEDOUT;
		case EINTR: 
			if (!interruptable)
				goto retry;
			atomic_add(&pf->count, 1); 
			return EINTR;
		default:
			RaiseError(IMPOSSIBLE__Can_not_lock_in_futex_sema_down);
		}
	}
	return 0;
}

/* Return value:
 *  1: wake up some waiter
 *  0: none is waiting
 */
static inline int
futex_sema_up(struct futex* pf)
{
	int retry;
    int n = atomic_add(&pf->count, 1);
	if (n < 0) {
        retry = 10;
		while (1 != (n=sys_futex(&pf->lock, FUTEX_WAKE, 1, NULL))) {
			/* it means the downer decreases the count but not yet start waiting 
			 *   --- may be interrupted near the retry label in the above function;
			 * so we have to wait and retry.
			 */
            if (retry --) { 
                nop(); 
            } 
            else { 
                retry = 10; 
                thread_yield();
            }
		}
		return n;
	}
	return 0;
}

/* Return value:
 *		   0: okay
 * ETIMEDOUT: timeout
 *     EINTR: interrupted
 */
static inline int 
futex_cond_wait(struct futex* pf, struct timespec* timeout, bool interruptable)
{
/* I dont know whether it is a bug of linux kernel.
 * Sometimes, sys_futex(.., FUTEX_WAIT, ..) returns 0, but the condition is not satisfied.
 * So we have to check the condition again after return.
 */
    while (0 < AtomicGetValue(pf->count)) {
        sys_futex(&pf->lock, FUTEX_WAIT, 0, timeout);
        switch (errno) {
		case ETIMEDOUT: 
			return ETIMEDOUT;
		case EINTR: 
            if (interruptable) {
			    return EINTR;
            }
        default:
            break;
		}
	}
	return 0;
//    int nnn;
//	int n = AtomicGetValue(pf->count);
//	if (0 != n) {
//retry:
//        //n = sys_futex(&pf->lock, FUTEX_WAIT, 0, timeout);
//        if (0 == sys_futex(&pf->lock, FUTEX_WAIT, 0, timeout)) {
//            nnn = errno;
//            int lock = AtomicGetValue(pf->lock);
//            int count = AtomicGetValue(pf->count);
//            UNLIKELY_IF (EAGAIN == errno) {
//                goto retry;
//            }
//            ASSERT_EQUAL(nnn, 0);
//            ASSERT_EQUAL(count, 0);
//			return 0;
//        }
//        
//		
//		switch (errno) {
//        case 0:
//            //ASSERT_EQUAL(pf->count, 0);
//            return 0;
//		case ETIMEDOUT: 
//			return ETIMEDOUT;
//		case EINTR: 
//			if (!interruptable)
//				goto retry;
//			return EINTR;
//		case EWOULDBLOCK:
//			// already signaled
//            nnn = AtomicGetValue(pf->lock);
//            ASSERT_EQUAL(nnn, 1);
//			return 0;
//		default:
//			RaiseError(IMPOSSIBLE__Can_not_lock_in_futex_cond_wait);
//		}
//	}
//	return 0;
}

/* Return value:
 *   the number of woken waiters
 */
static inline int
futex_cond_signal(struct futex* pf)
{
	int n = atomic_add(&pf->count, -1);
	if (1 == n) {
        pf->lock = 1;
        mfence_c();
		return sys_futex(&pf->lock, FUTEX_WAKE, 65535, NULL);	// I hope 65535 is enough to wake up all
	}
	return 0;
}

static inline int
futex_cond_revoke(struct futex* /*pf*/)
{
	// TODO:
	return 0;
}

/* Return value:
 *         0: okay
 * ETIMEDOUT: timeout
 *     EINTR: interrupted
 */
static inline int
futex_event_wait(struct futex* pf, struct timespec* timeout, bool interruptable)
{
    int n = atomic_add(&pf->count, 1);
    if (0 <= n) {    
retry:
        if (0 == sys_futex(&pf->lock, FUTEX_WAIT, 0, timeout))
            return 0;

        switch (errno) {
        case ETIMEDOUT: 
            atomic_add(&pf->count, -1); 
            return ETIMEDOUT;
        case EINTR: 
            if (!interruptable)
                goto retry;
            atomic_add(&pf->count, -1); 
            return EINTR;
        default:
            RaiseError(IMPOSSIBLE__Can_not_lock_in_futex_sema_down);
        }
    }
    else {  // else signaled
        AtomicSetValue(pf->count, LARGE_ENOUGH_NEGATIVE);
    }
    return 0;
}


/* Return value:
 *  the number of waiters if any
 */
static inline int
futex_event_signal(struct futex* pf, bool reset)
{
    int m, n, retry;

    n = AtomicSetValue(pf->count, reset ? 0 : LARGE_ENOUGH_NEGATIVE);
    if (0 < n) {
        retry = 10;
        m = n;
        do {
            n -= sys_futex(&pf->lock, FUTEX_WAKE, n, NULL);
            if (0 == n)
                return m;
            if (retry --) { 
                nop(); 
            } 
            else { 
                retry = 10; 
                thread_yield();
            }
        } while (1);
    }
    return 0;
}

static inline void
futex_event_reset(struct futex* pf) 
{
    int n, retry = 10;
    do {
        n = AtomicSetValueIf(pf->count, 0, LARGE_ENOUGH_NEGATIVE);
        if (0<=n || LARGE_ENOUGH_NEGATIVE==n) {
            return;
        }
        if (retry --) { 
            nop(); 
        } 
        else { 
            retry = 10; 
            thread_yield();
        }
    } while (1);
}

#ifdef	__cplusplus
}
#endif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 C++ 中,可以使用多种方式实现线程同步,以下是其中的几种: 1. 互斥锁(Mutex) 互斥锁是一种最常见的线程同步机制。它可以保证同时只有一个线程可以访问共享资源,其他线程需要等待该线程释放锁之后才能访问。C++ 中可以使用 `std::mutex` 类来创建互斥锁,使用 `lock()` 和 `unlock()` 函数来加锁和解锁。 ```c++ #include <iostream> #include <thread> #include <mutex> std::mutex mtx; // 创建互斥锁 void print(int num) { mtx.lock(); // 加锁 std::cout << num << std::endl; mtx.unlock(); // 解锁 } int main() { std::thread t1(print, 1); std::thread t2(print, 2); t1.join(); t2.join(); return 0; } ``` 在这个例子中,我们创建了一个互斥锁对象 `mtx`,并在 `print()` 函数中使用 `lock()` 和 `unlock()` 函数来加锁和解锁。在 `main()` 函数中,我们创建了两个线程 `t1` 和 `t2`,同时调用 `print()` 函数并传入不同的参数。由于互斥锁的存在,两个线程会交替输出数字 1 和 2。 2. 条件变量(Condition Variable) 条件变量是一种线程同步机制,它可以让线程在某个条件满足时才继续执行。C++ 中可以使用 `std::condition_variable` 类来创建条件变量,使用 `wait()` 函数等待条件,使用 `notify_one()` 或 `notify_all()` 函数唤醒等待的线程。 ```c++ #include <iostream> #include <thread> #include <mutex> #include <condition_variable> std::mutex mtx; // 创建互斥锁 std::condition_variable cv; // 创建条件变量 bool ready = false; void print(int num) { std::unique_lock<std::mutex> ulock(mtx); while (!ready) cv.wait(ulock); std::cout << num << std::endl; } int main() { std::thread t1(print, 1); std::thread t2(print, 2); std::this_thread::sleep_for(std::chrono::seconds(1)); { std::lock_guard<std::mutex> guard(mtx); ready = true; } cv.notify_all(); t1.join(); t2.join(); return 0; } ``` 在这个例子中,我们创建了一个互斥锁对象 `mtx` 和一个条件变量对象 `cv`,并在 `print()` 函数中使用了 `wait()` 函数等待条件。在 `main()` 函数中,我们创建了两个线程 `t1` 和 `t2`,并在一秒钟后唤醒两个线程。由于条件变量的存在,两个线程会等待条件满足后才会输出数字 1 和 2。 以上是两种常见的 C++ 线程同步机制,当然还有其他的同步机制,如信号量、屏障等。不同的同步机制适用于不同的场景,需要根据实际情况选择合适的机制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值