Bonjour,
J'essaie de faire un plugin de son en C# qui utilise du réseau.
J'ai donc besoin de faire un buffer circulaire de floats lock-free (et si possible wait-free)
(Pour le moment, je me fiche de la généricité)
Voici le code que j'ai actuellement :
J'ai encore du mal à voir ce qui est atomique ou non lorsque je fais mes opérations, et je me suis inspiré d'un code C++ pour faire ça.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96 public class BufferFloatCircularLockFree { // s_ : shared // r_ : local read method variables (to avoid allocatation) private int s_size; private float [] s_buffer; private int s_headRead; private int s_headWrite; private volatile int r_headRead; private volatile int r_headWrite; private volatile int r_headCopy; public BufferFloatCircularLockFree(int size) { s_size = size; s_buffer = new float[size]; s_headRead = 0; s_headWrite = 0; } public void Write(ref float f) { int headRead = s_headRead; int headWrite = s_headWrite; // queue full if ((headWrite + 1) % s_size == headRead % s_size) return; s_buffer[headWrite % s_size] = f; // no need for atomically increment here. s_headWrite ++; } public bool Read(ref float f) { do { // ensure thread safety. r_headRead = s_headRead; r_headWrite = s_headWrite; // queue empty or waiting if (r_headRead % s_size == r_headWrite % s_size) return false; f = s_buffer[r_headRead % s_size]; // try to perform CAS operation on the read index. // if(CAS(ref s_headRead, r_headRead, r_headRead + 1)) if (Interlocked.CompareExchange(ref s_headRead, r_headRead, r_headRead + 1) != r_headRead) return true; #error As it is now : infinite loop occurs. // didn't work. try again. } while (true) ; // impossible. //return false; } // CAS (Compare and swap) // --------------------- // // Does atomatically : // // public static bool CAS(ref int p, int old, int new) { // if(p != old) // return false; // p = new; // return true; // // return CompareExchange (ref p, old, new) != old; // } // // public static bool CompareExchange(ref int location1, int value, int comparand) // { // if(location1 == comparand) // location1 = value; // // return location1; // } public bool Read(float[] data) { for (r_headCopy = 0; r_headCopy < data.Length; r_headCopy++) if (!Read(ref data[r_headCopy])) return false; return true; } }
Le problème, comme le suggère mon #error, c'est que je me retrouve avec une boucle infinie assez rapidement.
(on arrête pas de lire et écrire dans le buffer).
Parmi ce que j'ai vu sur le web, il semblerait qu'il faille stocker des buffers dans une liste chaînée (et non pas les données dans un buffer).
Or, le nombre de samples (flottants) que j'écris est différent du nombre de samples que je dois lire (ces deux comptes sont variables).
Le problème c'est que mon thread audio doit faire le moins de calculs (pas beaucoup de temps), aucune allocation non plus et
que mon autre thread (qui gère le réseau notamment) doit fournir les données au plus vite.
Aucune idée de ce qui ne va pas dans le code ou dans le principe ?
Je vous remercie d'avance,
Sylafrs.
NB: .NET 2.0 car oui, c'est avec Unity3D/Android :p
Je ne peux donc pas utiliser SharedLibrary (qui utilise kernel32.dll, notemment et qui est .NET 3.5 min)
Je vais tenter l'approche C++ si je n'y arrive pas.
Partager