C#线程和断言不工作时出现问题
我试图解决程序中的一个问题,但无法完成。我遇到问题的部分是修饰符“leu_solde_du_compte_a_partir_de_plusieurs_threads() 当我尝试使用Decimal Solde返回变量时,它会返回一个随机值,而不是0。断言中返回的值必须等于0。请帮帮我 这是Visual Studio C#中的代码 谢谢你C#线程和断言不工作时出现问题,c#,multithreading,C#,Multithreading,我试图解决程序中的一个问题,但无法完成。我遇到问题的部分是修饰符“leu_solde_du_compte_a_partir_de_plusieurs_threads() 当我尝试使用Decimal Solde返回变量时,它会返回一个随机值,而不是0。断言中返回的值必须等于0。请帮帮我 这是Visual Studio C#中的代码 谢谢你 using System; public class CompteBancaire { public decimal solde1; publ
using System;
public class CompteBancaire {
public decimal solde1;
public bool bool_fermer = true;
public void Ouvrir()
{
solde1 = 0;
}
public void Fermer()
{
if (solde1 <= 0)
{
bool_fermer = false;
}
}
public decimal Solde
{
get
{
if (!bool_fermer)
{
throw new InvalidOperationException("");
}
return solde1;
}
}
/// <summary>
/// Mettre a jour le solde du compte bancaire.
/// </summary>
public void ReviserSolde(decimal change)
{
solde1 += change;
}
}
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xunit;
public class CompteBancaireTests
{
[Fact]
public void Retourne_un_solde_vide_apres_ouverture()
{
var compte = new CompteBancaire();
compte.Ouvrir();
Assert.Equal(0, compte.Solde);
}
[Fact]
public void Verifier_le_solde()
{
var compte = new CompteBancaire();
compte.Ouvrir();
var solde_a_l_ouverture = compte.Solde;
compte.ReviserSolde(10);
var solde_mis_a_jour = compte.Solde;
Assert.Equal(0, solde_a_l_ouverture);
Assert.Equal(10, solde_mis_a_jour);
}
[Theory]
[InlineData(10)]
[InlineData(20)]
public void Verifier_le_solde_random(int seed)
{
var compte = new CompteBancaire();
compte.Ouvrir();
var solde_a_l_ouverture = compte.Solde;
var random = new Random(seed).Next(0, 100);
compte.ReviserSolde(random);
var solde_mis_a_jour = compte.Solde;
Assert.Equal(0, solde_a_l_ouverture);
Assert.Equal(random, solde_mis_a_jour);
}
[Fact]
public void Le_solde_peut_augmenter_et_diminuer()
{
var compte = new CompteBancaire();
compte.Ouvrir();
var solde_a_l_ouverture = compte.Solde;
compte.ReviserSolde(10);
var ajouter_au_solde = compte.Solde;
compte.ReviserSolde(-15);
var soustraction_au_solde = compte.Solde;
Assert.Equal(0, solde_a_l_ouverture);
Assert.Equal(10, ajouter_au_solde);
Assert.Equal(-5, soustraction_au_solde);
}
[Fact]
public void Un_compte_ferme_lance_une_exception_lors_de_la_verification_du_solde()
{
var compte = new CompteBancaire();
compte.Ouvrir();
compte.Fermer();
Assert.Throws<InvalidOperationException>(() => compte.Solde);
}
[Fact]
public void Modifier_le_solde_du_compte_a_partir_de_plusieurs_threads()
{
var compte = new CompteBancaire();
var liste_de_tasks = new List<Task>();
const int nombre_de_threads = 500;
const int iterations = 100;
compte.Ouvrir();
for (int i = 0; i < nombre_de_threads; i++)
{
liste_de_tasks.Add(Task.Run(() =>
{
for (int j = 0; j < iterations; j++)
{
compte.ReviserSolde(1);
compte.ReviserSolde(-1);
}
}));
}
Task.WaitAll(liste_de_tasks.ToArray());
Assert.Equal(0, compte.Solde);
}
}
使用系统;
公营公司{
公共十进制solde1;
公共bool bool_fermer=true;
公共空间
{
solde1=0;
}
公开作废费默()
{
if(焊料1完整焊料);
}
[事实]
公共无效修饰符\u le_solde_du_compte_a_partir_de_plusieurs_threads()
{
var compte=新的CompteBancaire();
var liste_de_tasks=新列表();
const int nombre_de_线程=500;
常数int迭代=100;
compte.Ouvrir();
对于(int i=0;i
{
对于(int j=0;j
在ReviserSolde
中使用的操作+=
不是原子操作,因为它由多个线程调用,所以需要一些同步。例如,您可以修改单元测试,以便调用者处理它:
object locker = new object(); // create lock object
...
for (int i = 0; i < nombre_de_threads; i++)
{
liste_de_tasks.Add(Task.Run(() =>
{
for (int j = 0; j < iterations; j++)
{
lock (locker) // lock the modification
{
compte.ReviserSolde(1);
compte.ReviserSolde(-1);
}
}
}));
}
object locker=new object();//创建锁对象
...
对于(int i=0;i
{
对于(int j=0;j
或者您可以使ReviserSolde
线程安全(例如在那里添加lock
)
为了更深入地探讨这个话题,我通常推荐Albahari的。编辑:OP,我的答案——正如斯特隆大师所指出的——不是你想要的。为了让它在没有锁的情况下工作,它必须变得非常粗糙,而现在,它违背了多线程的目的 您的第一个for循环将在垃圾邮件线程/任务完成之前完成。这让我想到,在某个时刻,您的Task.WaitAll将发现没有剩下任何任务(即使您打算进一步迭代) 对我有效的是移动Task.WaitAll(liste_de_tasks.ToArray());进入第一个for循环,如下所示:
for (int i = 0; i < nombre_de_threads; i++)
{
liste_de_tasks.Add(Task.Run(() =>
{
for (int j = 0; j < iterations; j++)
{
compte.ReviserSolde(1);
compte.ReviserSolde(-1);
}
}));
Task.WaitAll(liste_de_tasks.ToArray());
}
for(int i=0;i
{
对于(int j=0;j
,例如@GuruStronsolde1
是一个十进制
,但尽管不能保证线程安全,但考虑到在任务之后预期会有输出,我不明白哪里会出现同步问题。WaitAll(…)
@Martin多线程(请参阅添加到liste_de_任务
)正在通过ReviserSolde
修改compte
的同一个实例(+=
不是一个原子操作),因此某些地方需要一些同步。我认为应该由“客户机”完成,即在嵌套循环中。@GuruStron是的,我完全理解代码。但是,该操作是使用500个任务执行的,每个任务加上和减去100次。如果您等待所有任务完成,0
@Martin再次,+=
不是原子的,那么最终结果将是相同的,例如,两个线程可以同时读取当前值(例如0
),然后添加1
,并将结果1
放在那里,在添加2次后,在solde
中给出1
。然后在减法过程中,不会发生这样的重叠,导致最后出现-1
。这将按顺序等待每个任务,基本上消除所有并行性,从而达到创建所有任务的目的,等等。您仍然会获得“一些”并行性,只是大大降低了。如果需要的话,你可以每100次做一次,但我明白你的意思。不,你不会。第一个创建的任务将立即等待,然后是第二个,依此类推。正如@guruston所指出的,这个答案完全没有意义。不要使用此解决方案。