当前位置: 首页 > 知识库问答 >
问题:

test_and_set使线程死锁

常茂
2023-03-14
#include<bits/stdc++++.h>
using namespace std;
int cnt=0;
int locked=0;
int test_and_set(int * lock){
    int temp=*lock;
    *lock=1;
    return temp;
}
void cntOnes(int t){
    while(test_and_set(&locked));

    for(int i=0;i<2000;i++){
        cnt++;
        cout<<t<<"  ->  "<<cnt<<endl;
    }
    locked=0;
}
int main(){
    thread t1(cntOnes,1);
    thread t2(cntOnes,2);
    t1.join();
    t2.join();
}

我使用test_and_set方法让其他线程先等待,线程t1可以中断while循环,但即使在线程t1将值设置为0之后。线程t2继续运行while循环,它不会中断while循环。应该做哪些改变?。

共有1个答案

荆亦
2023-03-14

首先,我为什么不应该#包含

不幸的是,有了这个,你的整个代码是一场伟大的大数据竞赛。如果不使用互斥或原子来同步它们,则根本无法使用普通变量在线程之间进行通信。在两个不同的线程中同时读取和写入普通变量是数据争用的定义,C标准说数据争用会导致未定义的行为(=使程序完全损坏)。

在许多可能出错的事情中:

> < li>

由于数据竞争规则,编译器假定普通变量在没有被该线程写入的情况下不会自发地改变值。因此,它认为<代码>而(测试和设置(

编译器同样假设没有其他线程在查看我们修改的普通变量。例如,由于它观察到运行< code>cntOnes的线程最终不可避免地要设置< code>locked = 0,它可以决定在2000步循环之前这样做。

您的test_and_html" target="_blank">set无论如何都不是原子的。即使加载和存储本身是原子的并且顺序一致(它们不是),操作也可以如下交错:

thread 1                               thread 2
========                               ========
temp = *lock; // temp = 0
                                       temp = *lock; // temp = 0
*lock = 1;
                                       *lock = 1;
return temp; // return 0               return temp; // return 0

现在,两个线程都认为它们持有锁。哦,亲爱的。

因此,您无法使用普通的int变量实现正确的“锁”。看起来你正试图重塑std::mutex,那么为什么不直接使用它呢?

#include <thread>
#include <iostream>
#include <mutex>

int cnt = 0;
std::mutex my_lock;

void cntOnes(int t) {
    my_lock.lock();
    for(int i=0; i<2000; i++) {
        cnt++;
        std::cout << t << "  ->  " << cnt << std::endl;
    }
    my_lock.unlock();
}

int main() {
    std::thread t1(cntOnes,1);
    std::thread t2(cntOnes,2);
    t1.join();
    t2.join();
}

或者更好,用std::scoped_lock来做RAII风格:

void cntOnes(int t) {
    std::scoped_lock<std::mutex> guard(my_lock);
    for(int i=0; i<2000; i++) {
        cnt++;
        std::cout << t << "  ->  " << cnt << std::endl;
    }
}

这里Guard的构造函数接受互斥锁,然后析构函数释放它。在C 17之前,您可以使用std::lock_guard,只要您只使用一个互斥锁。

如果你坚持做自己的测试和设置,那么你必须使用原子,例如std::atomic

另请参见:

>

  • num可以是'int num'的原子吗?

    C/C基本类型是原子的吗?

    C 11引入了标准化的内存模型。这是什么意思?它将如何影响C编程?

    如果您认为易失性 int 可能会解决您的问题,则不会:请参阅何时将易失性与多线程结合使用?

  •  类似资料:
    • 主要内容:1 什么是Java线程死锁,2 Java线程死锁的例子1 什么是Java线程死锁 Java中的死锁是多线程的一部分。当线程正在等待由另一个线程获取的对象锁而第二个线程正在等待由第一个线程获取的对象锁时,可能会发生死锁。由于两个线程都在互相等待释放锁,因此这种情况称为死锁。 2 Java线程死锁的例子 输出结果为:

    • 问题内容: 问题答案: 调用stop的替代方法是使用中断向线程发出信号,告知你希望它完成其工作。(这假设你要停止的线程行为良好,如果它在抛出异常后立即通过吃掉它们而忽略了InterruptedException,并且不检查中断状态,那么你将返回使用stop()。) 下面是一些代码,我写的一个答案,一个线程的问题在这里,它的线程中断,将如何工作的例子: 要注意的一些事情: 中断原因并立即抛出,否则你

    • 我有一个类似的问题,但是我知道当我要求阅读一行时,发件人应该发送一个行尾。 让我困惑的是,在调试中,它是有效的。可能是因为我在调试时跳过的顺序(直到现在我都不知道这会有什么不同),但我想更好地理解它。 我已经使用线程,但不是很多。 这是我的服务器类: 线程(基于此) 和客户: 它似乎在某个地方进入了死锁,出于某种原因,除非在调试中运行,否则永远不要在向客户端发送数据的服务器类上输入该死锁 (顺便说

    • 问题内容: 从技术上讲,Java中的线程自身可能死锁吗? 不久前,我在一次采访中被问到这是不可能的,但采访者告诉我这是可能的。不幸的是,我无法获得他的方法来解决这种僵局。 这让我开始思考,我唯一能想到的就是发生这种情况的地方是您拥有一个RMI服务器进程,其中包含一个调用自身的方法。调用该方法的代码行放置在同步块中。 甚至有可能还是面试官不正确? 我一直在考虑的源代码遵循这些原则(其中testDea

    • 本文向大家介绍什么是线程死锁?如何避免死锁?相关面试题,主要包含被问及什么是线程死锁?如何避免死锁?时的应答技巧和注意事项,需要的朋友参考一下 认识线程死锁 多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。 如下图所示,线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方的资源,所以这两个线程就会互相等待而进入死锁状态

    • 死锁描述了两个或多个线程永远被阻塞,等待彼此的情况。 当多个线程需要相同的锁但以不同的顺序获取它们时,会发生死锁。 Java多线程程序可能会遇到死锁条件,因为synchronized关键字会导致执行线程在等待与指定对象关联的锁定或监视器时阻塞。 这是一个例子。 例子 (Example) public class TestThread { public static Object Lock1